I have a component that consists of several other components such as text fields, and when an input is made to the text field, all other components are re-rendered.
I would like to prevent the re-rendering and only re-render the component that actually changes.
I have seen that useCallback
is the right way to do this and I have already seen how to use it. However, I'm having some trouble getting useCallBack
to work correctly for my case.
Even if I set it up in a simple manner as below, each new character entered into the text field causes the button to be rendered again.
I don't see my mistake.
See working example in sandbox.
const Button = () => {
console.log("Button Rendered!");
window.alert("Button Rendered");
return <button onClick="">Press me</button>;
};
export default function App() {
const [textInput, setTextInput] = useState("Hallo");
const onChangeInput = useCallback(
(e) => {
setTextInput(e.target.value);
},
[textInput]
);
return (
<div>
<input
type="text"
onChange={onChangeInput}
value={textInput}
/>
<Button />
</div>
);
}
I am happy for any calrification.
Memoization using useMemo() and UseCallback() Hooks Memoization enables your code to re-render components only if there's a change in the props. With this technique, developers can avoid unnecessary renderings and reduce the computational load in applications.
If you're using a React class component you can use the shouldComponentUpdate method or a React. PureComponent class extension to prevent a component from re-rendering.
By default, when we call this method, the component re-renders once it receives new props, even though the props have not changed. To prevent the render method from being called, set the return to false, which cancels the render. This method gets called before the component gets rendered.
If you don't want a component to re-render when its parent renders, wrap it with memo. After that, the component indeed will only re-render when its props change.
Personally I would avoid React.memo
/ React.useRef
/ React.useCallback
.
The simplest solution to your example is just create another component, and store the state with this.
eg.
const Button = () => {
console.log("Button Rendered!");
window.alert("Button Rendered");
return <button onClick="">Press me</button>;
};
const TextInput = () => {
const [textInput, setTextInput] = useState("Hallo");
const onChangeInput = useCallback(
(e) => {
setTextInput(e.target.value);
},
[textInput]
);
return (
<input
type="text"
onChange={onChangeInput}
value={textInput}
/>
);
}
export default function App() {
return (
<div>
<TextInput/>
<Button />
</div>
);
}
In the above if you change Text, there is not State change in App, so Button doesn't get re-rendered, no need for useMemo etc..
You will find React works really well, the more you divide your components up, not only does it solve issues of re-render, but potentially makes it a lot easier to re-use components later.
IOW: keep state as close to the component as possible, and performance will follow.
Of course your example is simple, and in a real app you will have HOC's etc to cope with, but that's another question.. :)
useCallback
does not prevent rerenders. React.memo
is what prevents renders. It does a shallow comparison of the previous props with the new props, and if they're the same, it skips rendering:
const Button = React.memo(() => {
console.log("Button Rendered!");
window.alert("Button Rendered");
return <button onClick="">Press me</button>;
});
The only role that useCallback plays in this is that sometimes you want to pass a function as a prop to a memoized component. For the memoization to work, props need to not change, and useCallback can help the props to not change.
changing the state causes re-render component along with all his heirs, to prevent re-render some sections, you can use useMemo to prevent unwanted re-rendering...
NOTE: useMemo has some costs... so don't overuse it (In this small example, it is not recommended at all).
in this case, if you do not need to re-rendering, you can use the useRef to save the input reference to get that value whenever you need it.
e.g:
const BlahBlah = () => {
const inputRef = React.useRef(undefined);
return (
<div>
<input ref={inputRef} />
<button onClick={() => console.log(inputRef.current.value)}
</div>
);
};
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With