Search code examples
javascriptreactjsfetch-api

Avoid re-fetching after re-rendering


The problem with my code is whenever I click toggle, the Child component re-render and request to the API gets called again. What I want is to request once, use that data even after re-rendering.

CodeSandbox

function Child() {
  const [data, setData] = useState("");

  useEffect(() => {
    console.log("fetching some data from server");
    setData(`this number should not change: ${Math.random().toString()}`);
  }, []);

  return <div>{data}</div>;
}

export default function Parent() {
  const [toggle, setToggle] = useState(false);
  const onToggle = () => {
    setToggle(!toggle);
  };

  return (
    <>
      <button onClick={onToggle}>Toggle</button>
      {toggle && <Child />}
    </>
  );
}

Solution

  • Here, you are not just re-rendering, infact you are re-mounting your Child component when you click the toggle button. If you want to not trigger the API call again, you should not re-mount the component.

    So, what you have to do is to remove the conditional check in {toggle && <Child />} and replace it with <Child />

    Then you can modify it slightly, by pass the toggle state to the Child component like <Child show={toggle}/> and then return null from Child in cases where you previously did not want to render it.

    function Child(props) {
      const [data, setData] = useState("");
    
      useEffect(() => {
        console.log("fetching some data from server");
        setData(`this number should not change: ${Math.random().toString()}`);
      }, []);
      
      if (props.show) {
        return <div>{data}</div>;
      }
      return null
    }
    
    export default function Parent() {
      const [toggle, setToggle] = useState(false);
      const onToggle = () => {
        setToggle(!toggle);
      };
    
      return (
        <>
          <button onClick={onToggle}>Toggle</button>
          <Child show={toggle}/>
        </>
      );
    }