I'm using latest create-react-app
config and facing the issues when switching between different routes.
All my SVG
's are included in sprite file. Logically, sprite.svg file should be cached on the first-page load.
But instead, every change of route (with react-router
4) loads this file which causes flickering. Content changes instantly, but images loads with 1s lag.
Same for png
included via import
in jsx
.
From what I cant see in the console, same files download over and over again.
Live demo at http://cabin.surge.sh/ (i.e. try to change between Pricing / About pages in the header section)
Update:
The way I include SVG image - is dumb component <SvgIcon name="checkmark" />
import React, { Component } from 'react';
import sprite from '../images/sprite.svg';
export default class SvgIcon extends Component {
render(){
const { name } = this.props;
return(
<svg className={"ico ico-" + name}>
<use xlinkHref={sprite + "#ico-" + name}></use>
</svg>
)
}
}
PNG images
<img src={require(`../images/${authorImage}.png`)} srcSet={require(`../images/${authorImage}@2x.png`) + ' 2x'} alt=""/>
The reason you get a 200
instead of 304
is that you have a service worker which will intercept the request and serve the same from the cache itself. Which itself is 200
response. If you disable the service worker then you will get a 304
If the problem is that the image is not fetched earlier and causing flickering on page change, try to use
componentDidMount() {
const sprite = "../images/sprite.svg";
const prefetchLink = document.createElement("link");
prefetchLink.href = sprite;
prefetchLink.rel = "prefetch";
prefetchLink.as = "image";
document.body.appendChild(prefetchLink);
}
This will hint the browser to fetch resources in the background (idle time) that might be needed later, and store them in the browser’s cache. Once a page has finished loading it begins downloading additional resources and if a user then clicks on a prefetched link, it will load the content instantly.
For a functional version:
//custom hook to preload image
const usePreload = (url) => {
const [loaded, setLoaded] = React.useState(false);
const onLoad = React.useCallback(() => {
setLoaded(true);
}, []);
React.useEffect(() => {
const prefetchLink = document.createElement('link');
prefetchLink.href = url;
prefetchLink.rel = 'prefetch';
prefetchLink.as = 'image';
prefetchLink.addEventListener('load', onLoad);
document.body.appendChild(prefetchLink);
//clean up
return () => document.body.removeChild(prefetchLink);
}, [onLoad, url]);
return loaded;
};
export default function SvgIcon({ name }) {
const url = sprite + '#ico-' + name;
const loaded = usePreload(url);
return (
loaded && ( //only render if image is loaded
<svg className={'ico ico-' + name}>
<use xlinkHref={url}></use>
</svg>
)
);
}
Note that if you do server side rendering you don't want this code to execute on the server because there is no document
on the server.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With