Signals are another way of managing application state.
You might ask, “well great but we already have hooks like useState so what’s the point?”
In answer to the above perfectly valid question, Signals work on a in a more granular way – let’s compare to useState. If we create a simple little (and pretty standard) counter component we can immediately see the differences.
Create yourself a React application, I’m using yarn but use your preferred package manager.
yarn create react-app react-with-signals --template typescript
Add the signal package using
yarn add @preact/signals-react
Now we’ll create a folder named components and add a file named CounterState.tsx which looks like this
import { useState } from "react"; export const CounterState = () => { const [count, setCount] = useState(0); console.log("Render CounterState"); return ( <div> <div>Current Value {count}</div> <div> <button onClick={() => setCount(count - 1)}>Decrement</button> <button onClick={() => setCount(count + 1)}>Increment</button> </div> </div> ); }
It’s not very pretty but it’s good enough for this demonstration.
Finally create a new file in the components folder named CounterSignals.tsx which should look like this
import React from 'react'; import { useSignal } from "@preact/signals-react"; export const CounterSignals = () => { const count = useSignal(0); console.log("Render CounterSignals"); return ( <div> <div>Current Value {count}</div> <div> <button onClick={() => count.value--}>Decrement</button> <button onClick={() => count.value++}>Increment</button> </div> </div> ); }
As you can see, the Signals code creates a Signals object instead of the destructuring way used with useState and the Signals object will not change, but when we change the value, the value within the object changes but does not re-rendering the entire component each time.
Let’s see this by watching the console output in our preferred browser, so just change App.tsx to look like this
import React from ‘react’;
import { CounterState } from ‘./components/CounterState’;
import { CounterSignals } from ‘./components/CounterSignals’;
function App() {
return (
);
}
export default App;
[/em]
Start the application. You might wish to disable React.StrictMode in the index.tsx as this will double up the console output whilst in DEV mode.
Click the Increment and Decrement buttons and you’ll see our useState implementation renders on each click whereas the counter changes for the Signals version but no re-rendering happens.
Code
Code for this example using Signals can be found on github.