I had this same problem, until I read the Deep Dive section in Fetching data with Effects in the React docs.
The relevant bit is:
This list of downsides is not specific to React. It applies to
fetching data on mount with any library. Like with routing, data
fetching is not trivial to do well, so we recommend the following
approaches:
- If you use a framework, use its built-in data fetching mechanism. Modern React frameworks have integrated data fetching mechanisms that
are efficient and don’t suffer from the above pitfalls.
- Otherwise, consider using or building a client-side cache. Popular open source solutions include React Query, useSWR, and React Router
6.4+. You can build your own solution too, in which case you would use Effects under the hood but also add logic for deduplicating requests,
caching responses, and avoiding network waterfalls (by preloading data
or hoisting data requirements to routes).
In my case useSWR was already part of the project dependencies and looking at the example it is quite simple to use:
import useSWR from 'swr'
function Profile() {
const { data, error, isLoading } = useSWR('/api/user', fetcher)
if (error) return <div>failed to load</div>
if (isLoading) return <div>loading...</div>
return <div>hello {data.name}!</div>
}
Afterwards I verified that the Fetch only happens once, happy days...
So for your code that would be something like:
import useSWR from 'swr'
const App => {
const [image, SetImage] = useState('');
async function fetchImage(url) {
//...
await response = fetch(url);
SetImage(response);
}
const { data, error, isLoading } = useSWR('API-to-get-base64image', fetchImage)
return (
<div><img src={image}/> </div>
)
}