Signals are specifically designed for managing client-side state and have been adopted by multiple JavaScript frameworks such as Angular, Vue, SolidJS, Qwik, and Preact. Their characteristic is the ability to automatically track the precise location where a variable is used. When the value of the variable changes, it triggers an immediate update or re-render of the interface.
For example, here is a Signal initialized with a value of 0:
const counter = new Signal.State(0);
It’s worth noting that Signals are fundamentally different from React’s useState
. The latter is a hook in React that allows developers to declare and update state variables within functional components. Signals, however, are more like event listeners or observers, used to deal with asynchronous events or data changes that fall outside the direct control of components.
So how can Signals be applied in React? A signal can be declared as simply as this:
const [counter, setCounter] = useState(0);
The intriguing part about Signals is that they offer a different model for state management, allowing for more granular control over which parts of the UI need to rerender, in contrast to React’s “top-down” update model. However, this does not necessarily mean Signals have a performance advantage; rather, their functional differences provide them with different use cases.
To use Signals, we can declare a new Signal in the following way:
const counter = new Signal.State(0);
To get the value of a Signal, we use the get()
method; to set or update the value of a Signal, we use the set()
method.
The application of Signals in React differs from their traditional usage; essentially, they are combined with React’s declarative programming, sticking to the use of the Virtual DOM (VDOM) and prompting components to rerender in a manner similar to the mechanism triggered by updating useState. So, what is the purpose of using Signals in React? This is actually a question many people have when they first encounter Signals. But this is precisely the area we need to explore in depth.
If the TC39 proposal is approved, this means that Signals will become a native feature of the JavaScript language, allowing us to use Signals outside of frameworks. This is particularly meaningful for framework developers, as they will be able to implement the Signals feature in a standardized manner. Furthermore, any improvements to the Signals mechanism will benefit all frameworks that follow this standardized approach. Currently, various frameworks that adopt the Signals mechanism each have their own unique implementations. Notably, Rob Eisenberg announced on April 11th that this proposal has entered the first stage of TC39, meaning that it has started to be formally considered by ECMAScript. Although there is still much work to be done, the proposal is moving in a positive direction.
The TC39 proposal also highlights the importance of developing APIs that cater to the needs of different frameworks. For React, use-signals attempts to implement the proposed Signals API use while adhering to its core design principles. Regardless of whether the React team ultimately adopts Signals or not, the existence of use-signals has already demonstrated the potential of Signals in React to some extent.
Aside from the currently supported primitives, the signal-utils proposal is endeavoring to include objects and arrays as well. For example, managing object state with SignalObject:
import { SignalObject } from 'signal-utils/object';
let obj = new SignalObject({
isLoading: true,
error: null,
result: null,
});
Or managing array state with SignalArray:
import { SignalArray } from 'signal-utils/array';
let arr = new SignalArray([1, 2, 3]);
To better understand how to utilize Signals in React, the following is an example demonstration of its application.
In the Waku context, the example React code is primarily server-side rendered, but also supports pure client-side components with the use of the “use client” directive. The difference between Signals and useState is that Signals are declared outside of the component. As defined in the code below, a variable named counter that stores the initial value is imported into the useSignal hook. This counter variable provides .set() and .get() methods, which are used in the event handler handleInc.
The updating of the Signal value triggers a re-render of the DOM and displays the updated count value on the user interface. It is particularly noteworthy that in the returned JSX, we no longer need to call the .get() method to retrieve and display the value in the <div> element; the count value can now be directly referenced. This is different from the Qwik framework, where we need to retrieve the value from counter.value.
‘use client’;
import { Signal, useSignal } from ‘use-signals’;
const counter = new Signal.State(0);
const UseSignalComponent = () => {
const count = useSignal(counter);
const handleInc = () => counter.set(counter.get() + 1);
return (
<>
</>
);
};
export default UseSignalComponent;
useState Component
For an intuitive comparison, the code below is written using React’s useState hook, keeping the business logic unchanged. From an implementation perspective, there isn’t much difference.
‘use client’;
import { useState } from ‘react’;
const UseStateComponent = () => {
const [count, setCount] = useState(0);
const handleInc = () => setCount(count + 1);
return (
<>
</>
);
};
export default UseStateComponent;
Mixed Signals
In summary, using Signals in React is entirely feasible.
Although Signals may have to wait a while before becoming a native feature in the JavaScript world, its rapid growth in the tech community and exploration of innovative development models have garnered widespread acclaim. Developers interested in this can continue to keep an eye on the Signals repository on GitHub.
Additionally, it’s worth mentioning that several noteworthy events have occurred recently in the tech field. Germany decided to switch back to Linux, migrating tens of thousands of systems from Windows, sparking discussions on how to avoid repeating the issues from two decades ago. Google’s decision for massive layoffs has met with collective protests, including from some senior employees, questioning the expansion of the management and middle management teams and their efficiency. Furthermore, a system bug that caused innocent people to be jailed has drawn wide public attention. Even after investing hundreds of millions of yuan in an attempt to adopt cloud services, the problem remains unsolved. Behind these events, we can see that even giant corporations can suffer greatly from the wrong choice of software. Finally, open-source veteran Linus Torvalds has once again spoken about the use of the Tab key versus the space bar, issuing new guidelines.