Code Review. Scroll by using RAF

 avatar
ilyasidorchik
jsx
10 months ago
1.7 kB
21
Indexable
import React, { useEffect, useRef, useCallback, useState } from 'react';
import Item from './Item';
import './style.css';

export default function App() {
  const [count, setCount] = useState(0);
  const topRef = useRef<HTMLDivElement>(null);
  const rafIdRef = useRef<number | null>(null);

  const updatePos = useCallback((y: number) => {
    const el = topRef.current;
    if (!el) return;

    if (y > 100) {
      // меняем только композитное свойство
      el.style.willChange = 'transform';
      el.style.transform = `translateY(${y}px)`;
    } else {
      el.style.transform = 'translateY(0)';
      el.style.willChange = '';
    }
  }, []);

  useEffect(() => {
    const onScroll = () => {
      const y = window.scrollY;
      if (rafIdRef.current != null) cancelAnimationFrame(rafIdRef.current);
      rafIdRef.current = requestAnimationFrame(() => updatePos(y));
    };

    window.addEventListener('scroll', onScroll, { passive: true });
    // начальное положение
    updatePos(window.scrollY);

    return () => {
      window.removeEventListener('scroll', onScroll);
      if (rafIdRef.current != null) cancelAnimationFrame(rafIdRef.current);
    };
  }, [updatePos]);

  const handleAdd = useCallback(() => setCount(prev => prev + 1), []);

  return (
    <div className="App">
      <div className="block-wrapper">
        <div className="top-section" ref={topRef}>
          <button type="button" onClick={() => alert(count)}>Show count</button>
          <button type="button" onClick={() => setCount(0)}>Reset count</button>
        </div>
        {[...Array(6)].map((_, i) => (
          <Item key={i} onAdd={handleAdd} />
        ))}
      </div>
    </div>
  );
}
Editor is loading...
Leave a Comment