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
- Swap to native loading="lazy"and compare behavior.
- Add retry button on error.
Checks for Understanding
- What benefit do skeletons provide compared to spinners?
- How do you avoid layout shift when images load?
Show answers
- They reserve space and convey structure, reducing perceived wait time.
- Reserve dimensions with a fixed box or aspect-ratio container.