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