javascriptreactjsreact-nativereact-hooks

How can I prevent re-rendering of components that have not changed?


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.

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>
  );
}

Solution

  • 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 = (e) => {
          setTextInput(e.target.value);
      };
      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.