From my parent component, I am passing down the state variable data as a prop to the child component. The data is fetched via fetch/UseEffect. The URL params can be modified by clicking a button, and depending on the param, a completely different object is fetched, which needs to be handled differently in the child component.
export default function ParentComponent() {
const [data, setData] = useState({})
const [param, setParam] = useState('')
const [isLoading, setLoading] = useState(true)
useEffect(() => {
const fetchData = async () => {
const data= await (await fetch(`https://myapi.com/?param=${param}`)).json()
setData(data)
setLoading(false)
}
fetchData()
}, [param])
return (<div>
{ isLoading ?
(<span>Loading...</span>)
:
(<div>
<button onClick={() => setParam('something')}>Click me</button>
<ChildComponent data={ data } />
</div>
</div>)
}
}
My problem is that whenever I click the button (set the state) in the parent, which triggers a rerender, the components rerender twice (causing below console.log to print twice), which I'd dare say is expected behavior, once because of setParam, once when fetchData and setData is completed).
export default function ChildComponent(props) {
const { data } = props
return (
<div>
// Prints twice, first stale data, then when fetchData has completed.
{ console.log(data )}
</div>)
}
My question to you guys, as I have been struggling with this for a couple of hours now, having read ChrisW's post here (Avoid old data when using useEffect to fetch data) and the React.js Hooks FAQ (https://reactjs.org/docs/hooks-faq.html), is how on God's green earth (sorry any atheist!) I only ever get to access the newly fetched, non-stale data prop in the child component, and ignore the stale one? Is it through refs? UseEffect? (I know I can make a UseEffect in the child component with data as a dependency, however, what should I do with it, I am after all trying to control what is being returned?)
Thanks in advance for any answers!
I would suggest to consider useMemo API to solve this issue:
const MemoizedChildComponent = useMemo(({ data }) => <ChildComponent data={data} />, [data]);