react-hook-useobserver
v1.0.0-alpha.19
Published
Avoid excessive re-rendering in your React app by using `useObserver` and `useObserverListener` as an alternative to `useState`.
Downloads
26
Readme
React Hook useObserver.
Avoid excessive re-rendering in your React app by using useObserver
and useObserverListener
as an alternative to useState
.
Both useState
is frequently used hook. However, when you use the setState function, useState will immediately re-render the component.
Most of the time, we don't want to re-render the component right away,
and we want to make sure that we're re-rendering the component that listens to the change of a specific attribute
in the state only. As an alternative, we can utilize useObserver to fix this problem.
The following are examples of common uses of useState.
import React, { useState } from 'react';
import {DataGrid} from './DataGrid'
function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);
return (
<div>
<DisplayCount count={count} />
<button onClick={() => setCount(count + 1)}>
Click me
</button>
<DataGrid/>
</div>
);
}
function DisplayCount({count}){
return <p>You clicked {count} times</p>
}
The preceding scenario is an illustration of a common re-rendering issue in React application. We have an Example
component with a state count
,
and Example
component render the DataGrid
component. In general, the DataGrid
component is huge and contains numerous rows.
If we don't conduct performance optimization, such as using React.memo
, we will run into performance issue because React will re-render
the entire component when the function from setCount
is called.
An alternative to the above method using the useObserver is as follows:
import React, { useState } from 'react';
import {VeryComplexChart} from './VeryComplexChart'
function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useObserver(0);
return (
<div>
<DisplayCount count={count} />
<button onClick={() => setCount(count + 1)}>
Click me
</button>
<VeryComplexChart/>
</div>
);
}
function DisplayCount({count}){
return <p>You clicked {useObserverValue(count)} times</p>
}
By changing useObserver
instead, we have simply ensured that the DataGrid will not be re-rendered when setCount
is invoked.
When the setCount
component is called, just the DisplayCount component is re-rendered.
What does calling useObserver do?
const [count,setCount] = useObserver(0);
It declares a observable
variable. Our variable is called count, but we could call it anything else, like banana.
This is a way to “preserve” some values between the function calls — useObserver is a new way to use the exact same
capabilities that useState
provides in react hook.
The primary distinction between useObserver
and useState
is the useObserver function's return an array of mutable values
as well as the function used to setValue
. The mutable value returned by useObserver
is identical to the one returned by useRef
.
As a result, we can utilize a property called "current" to access the current value of count.
return <div>{count.current}</div>
What are the benefits of using the useObserver?
useObserver will not re-render the component to which it is attached. So, if the component that utilizes useObserver hooks has extensive and complicated children, re-rendering, and performance degradation can be avoided.
How to listen if an observer is updated
To find out if an observer is updated when setValue is called, add an event listener to the observer itself. So basically we can rewrite our example above to something like this.
function Example() {
const [count, setCount] = useObserver(0);
return (
<div>
<DisplayCount count={count} />
<button onClick={() => setCount(count + 1)}>
Click me
</button>
<VeryComplexChart/>
</div>
);
}
function DisplayCount({count}){
const [countValue,setCountValue] = useState(count.current);
useEffect(() => {
const removeListener = count.addListener((newCount,oldCount) => {
setCountValue(newCount);
});
return () => removeListener();
},[]);
return <p>You clicked {countValue} times</p>
}
The above code is an extended version of what we would do if we wanted to listen to the value of useObserver.
We can use useObserverListener
hook instead using useEffect to add event listener to the observer.
import {useObserverListener} from "./useObserverListener";
function DisplayCount({count}) {
const [countValue,setCountValue] = useState(count.current);
useObserverListener(count,(newCount) => {
setCountValue(newCount);
})
return <p>You clicked {countValue} times</p>
}
We can cut the code above in half by utilizing the useObserverValue hook to receive the value from the observer.
import {useObserverValue} from "./useObserverValue";
function DisplayCount({count}) {
const countValue = useObserverValue(count);
return <p>You clicked {countValue} times</p>
}
By using useObserver you can avoid excessive re-rendering of react.