Irbisa · Шпаргалка
Эффекты и рефы
useEffect и зависимости, cleanup, гонки запросов, когда эффект не нужен, useRef, useLayoutEffect, двойной запуск в StrictMode
Для чего нужен
useEffectи когда он выполняется?function ChatRoom({ roomId }: { roomId: string }) { useEffect(() => { const connection = createConnection(roomId); connection.connect(); return () => connection.disconnect(); // runs before the next effect and on unmount }, [roomId]); // reconnect only when roomId changes…Как работает массив зависимостей
useEffect: без массива, с пустым массивом и со списком значений?useEffect(() => { document.title = `${count} new messages`;}); // after every render useEffect(() => { const id = setInterval(refreshClock, 1000);…Что такое функция очистки (cleanup) у эффекта и когда React её вызывает?
function useWindowWidth() { const [width, setWidth] = useState(window.innerWidth); useEffect(() => { const onResize = () => setWidth(window.innerWidth); window.addEventListener('resize', onResize);…Что такое
useRefи чем он отличается от стейта?function Stopwatch() { const [elapsed, setElapsed] = useState(0); // shown on screen: state const intervalRef = useRef<number | null>(null); // not shown: ref function start() { if (intervalRef.current !== null) return;…Как получить доступ к DOM-элементу через ref и как передать ref в свой компонент в React 19?
function TextInput({ ref, ...props }: React.ComponentProps<'input'>) { return <input ref={ref} className="input" {...props} />;} function SearchForm() { const inputRef = useRef<HTMLInputElement>(null);…Почему в режиме разработки эффекты срабатывают дважды и что с этим делать?
Что такое гонка (race condition) при загрузке данных в
useEffectи как её предотвратить?type Hit = { id: string; title: string }; function SearchResults({ query }: { query: string }) { const [results, setResults] = useState<Hit[]>([]); useEffect(() => {…Когда эффект не нужен и что использовать вместо него?
Найдите баг: этот эффект крутится в бесконечном цикле и без остановки шлёт запросы.
function Products({ category }: { category: string }) { const [products, setProducts] = useState<Product[]>([]); const filters = { category, inStock: true }; useEffect(() => { fetchProducts(filters).then(setProducts); }, [filters]); return <ProductGrid items={products} />;}Найдите баг: React пишет «useEffect must not return anything besides a function», а при смене
userIdстраница становится пустой.function Profile({ userId }) { const [user, setUser] = useState(null); useEffect(async () => { const response = await fetch(`/api/users/${userId}`); setUser(await response.json()); }, [userId]); return <h1>{user ? user.name : 'Loading...'}</h1>;}Что выведет этот компонент в консоль при монтировании и после одного клика (без StrictMode)?
function Logger() { const [count, setCount] = useState(0); console.log('render', count); useEffect(() => { console.log('effect', count); return () => console.log('cleanup', count); }, [count]); return <button onClick={() => setCount(count + 1)}>{count}</button>;}Как реализовать хук
usePreviousи какие у него ограничения?// classic: the value from the previous renderfunction usePrevious<T>(value: T): T | undefined { const ref = useRef<T | undefined>(undefined); useEffect(() => { ref.current = value; });…Найдите баг: счётчик доходит от 0 до 1 и дальше не растёт.
function Ticker() { const [count, setCount] = useState(0); useEffect(() => { const id = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(id); }, []); return <p>{count}</p>;}Чем
useEffectотличается отuseLayoutEffectи когда нужен второй?function Tooltip({ anchor, text }: { anchor: DOMRect; text: string }) { const ref = useRef<HTMLDivElement>(null); const [top, setTop] = useState(anchor.bottom); useLayoutEffect(() => { if (!ref.current) return;…Что такое
useImperativeHandleи когда стоит открывать методы через ref?type VideoHandle = { play: () => void; pause: () => void }; function Video({ src, ref }: { src: string; ref?: React.Ref<VideoHandle> }) { const videoRef = useRef<HTMLVideoElement>(null); useImperativeHandle(ref, () => ({…Как закрыть выпадающее меню, когда пользователь кликает за его пределами?
function Dropdown({ items }: { items: string[] }) { const [open, setOpen] = useState(false); const rootRef = useRef<HTMLDivElement>(null); useEffect(() => { if (!open) return;…Как использовать внутри React-компонента библиотеку, которая сама управляет своим DOM, например карту или график?
import Chart from 'chart.js/auto'; function SalesChart({ labels, values }: { labels: string[]; values: number[] }) { const canvasRef = useRef<HTMLCanvasElement>(null); const chartRef = useRef<Chart<'line', number[], string> | null>(null);…Как читать актуальные пропсы или стейт внутри эффекта, не перезапуская его, и что такое
useEffectEvent?import { useEffect, useEffectEvent } from 'react'; function ChatRoom({ roomId, theme }: { roomId: string; theme: 'light' | 'dark' }) { const onConnected = useEffectEvent(() => { showNotification('Connected!', theme); // reads the latest theme });…Что такое колбэк-рефы и что в них изменилось в React 19?
function MeasuredBox({ children }: { children: React.ReactNode }) { const [height, setHeight] = useState(0); const measure = useCallback((node: HTMLDivElement) => { const observer = new ResizeObserver(([entry]) => setHeight(entry.contentRect.height)); observer.observe(node);…