React - Loading Images from Network

Overview

Estimated time: 20–30 minutes

Load images efficiently with lazy-loading, skeleton placeholders, and error fallbacks.

Try it: Lazy image list

View source
function LazyImg({src, alt}){
  const ref = React.useRef(null);
  const [state, setState] = React.useState('idle'); // idle|loading|loaded|error
  const [inView, setInView] = React.useState(false);
  React.useEffect(() => {
    const el = ref.current; if (!el) return;
    const io = new IntersectionObserver(([e]) => { if (e.isIntersecting) setInView(true); }, {rootMargin:'200px'});
    io.observe(el); return () => io.disconnect();
  }, []);
  return (
    <div ref={ref} style={{height:160, position:'relative', background:'#eee', display:'grid', placeItems:'center'}}>
      {state!=='loaded' && <div className="skeleton" style={{position:'absolute', inset:0, animation:'pulse 1.2s infinite'}}></div>}
      {inView && <img alt={alt} src={src} onLoad={() => setState('loaded')} onError={() => setState('error')} style={{width:'100%', height:'100%', objectFit:'cover', display: state==='loaded'? 'block':'none'}} />}
      {state==='error' && <div>⚠️ Failed to load</div>}
    </div>
  );
}
function App(){
  const imgs = Array.from({length:20}, (_,i)=> `https://picsum.photos/seed/${i+1}/600/400`);
  return <div style={{display:'grid', gap:12}}>{imgs.map((src,i)=> <LazyImg key={i} src={src} alt={`Img ${i+1}`} />)}</div>;
}
ReactDOM.createRoot(document.getElementById('try-imgs')).render(<App />);

Syntax primer

  • IntersectionObserver triggers loading when images near the viewport.
  • Use skeletons to reduce perceived load time.

Common pitfalls

  • Not reserving space for images—causes layout shift.

Exercises

  1. Swap to native loading="lazy" and compare behavior.
  2. Add retry button on error.

Checks for Understanding

  1. What benefit do skeletons provide compared to spinners?
  2. How do you avoid layout shift when images load?
Show answers
  1. They reserve space and convey structure, reducing perceived wait time.
  2. Reserve dimensions with a fixed box or aspect-ratio container.