Subscribe
We explained the subscribe method in the previous sections. But we will discuss it a little more in this section.
In most cases, we need a re-render in our React component after changing the state values. But in some cases, it is necessary to monitor the state changes without making additional re-render. In this case, we can use the subscribe
method available in the observer
.
The subscribe method can be used in two different parts of the app.
- Outside the React component.
- Inside the useEffect hook in the React component.
Note that you should not use the subscribe
method inside the body
of your component. Because by doing this, you subscribe separately for the state changes by each re-render, which itself causes additional overhead.
Subscribing outside the React component
import { observer, useObserver } from 'rosma';
observer.subscribe('time', listener);
function listener(time) {
alert('The time is ' + time);
}
export function Component() {
const { time, setTime } = useObserver();
return (
<div>
<p>{time}</p>
<button onClick={() => setTime(new Date().toLocaleTimeString())}>
Click to update
</button>
</div>
);
}
In this example, we subscribe to the time
value using the observer.subscribe
function, and we provide a listener
function for observing the updates of the time value. The listener
function simply displays an alert with the current time.
The Component
function is a React functional component that uses the useObserver
hook to access the current time
value, and the setTime
function to update it.
Note that the listener
function is called before the component is re-rendered, which means that any changes made to the time
value will be reflected in the component's UI when it next re-renders.
Subscribing inside the React component
Note that to subscribe inside a React component, we must put the subscribe operation inside the useEffect
hook.
Also, another important point is that the subscribe method returns a function to unsubscribe
, which must be called when our component is unmounted
.
Here we have rewritten the same previous example for use in this section:
import { useEffect } from 'react';
import { observer, useObserver } from 'rosma';
export function Component2() {
const { time, setTime } = useObserver();
useEffect(() => {
const unsubscribe = observer.subscribe('time', listener);
function listener(time) {
alert('The time is ' + time);
}
return () => unsubscribe();
}, []);
return (
<div>
<p>{time}</p>
<button onClick={() => setTime(new Date().toLocaleTimeString())}>
Click to update
</button>
</div>
);
}
subscribing for more than one value
You can monitor changes to multiple values by using a single listener function. To do this, instead of passing a single string as the first parameter to the subscribe
method, you need to pass an array of strings.
import { observer, useObserver } from 'rosma';
observer.subscribe(['random1', 'random2'], listener);
function listener({ random1, random2 }) {
alert(`Random1: ${random1},\nRandom2: ${random2}`);
}
function Component1() {
const { random1, setRandom1 } = useObserver();
return (
<button onClick={() => setRandom1(Math.random())}>
{random1 || 'Random1'}
</button>
);
}
function Component2() {
const { random2, setRandom2 } = useObserver();
return (
<button onClick={() => setRandom2(Math.random())}>
{random2 || 'Random2'}
</button>
);
}
export function App() {
return (
<>
<Component1 />
<Component2 />
</>
);
}
In this example, we subscribe to the random1
and random2
values by passing an array of their names to the observer.subscribe
function. We also provide a single listener
function that receives an object containing the current values of both random1
and random2
. The listener
function simply displays an alert with the current values of both random1
and random2
.
We then define two separate functional components, Component1
and Component2
, which use the useObserver
hook to access the current values of random1
and random2
respectively. Each component also provides a button that, when clicked, updates the corresponding value using the setRandom1
or setRandom2
function provided by the useObserver
hook.
Finally, we render both Component1
and Component2
in the App
component, so that changes to both random1
and random2
can be monitored by the listener
function. Note that any changes made to either random1
or random2
will be reflected in the corresponding component's UI when it next re-renders.
Subscribing for every state changes
To observe changes for all state values, you can use the *
key in place of an array of value names when subscribing. This will allow you to listen to changes for all values in the state.
Here is an example:
import { observer, useObserver } from 'rosma';
observer.subscribe('*', listener);
function listener({ random1, random2 }) {
if ((random1 || random2) === undefined) return;
alert(`Random1: ${random1},\nRandom2: ${random2}`);
}
function Component1() {
const { random1, setRandom1 } = useObserver();
return (
<button onClick={() => setRandom1(Math.random())}>
{random1 || 'random1'}
</button>
);
}
function Component2() {
const { random2, setRandom2 } = useObserver();
return (
<button onClick={() => setRandom2(Math.random())}>
{random2 || 'Random2'}
</button>
);
}
export function App() {
return (
<>
<Component1 />
<Component2 />
</>
);
}
In this example, we use the *
key as the first parameter to the subscribe
method to listen to changes in all state values. The listener
function receives the entire state object as an argument, and we can access the values we're interested in by destructuring the state object.
Keywords: Rosma, observer, useObserver, state, state management, subscribing to state changes, subscribing to multiple state values, React, functional components, component re-rendering
Previous: Multiple observers
Next: withState