← Назад к вопросам

Какие знаешь Hook?

1.2 Junior🔥 221 комментариев
#React

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI23 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

React Hooks: полный обзор

Hooks — это функции, которые позволяют использовать state и другие функции React в функциональных компонентах. Они были введены в React 16.8 и стали стандартом разработки, заменив классовые компоненты.

Основные правила использования Hooks

  1. Вызывай hooks только на верхнем уровне — не в циклах, условиях или вложенных функциях
  2. Вызывай hooks только в React компонентах — в функциональных компонентах или кастомных hooks
  3. Используй ESLint плагин для проверки правил

1. useState — управление состоянием

const [count, setCount] = useState<number>(0);
const [name, setName] = useState<string>('');
const [user, setUser] = useState<User | null>(null);

function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <div>
      <p>Счетчик: {count}</p>
      <button onClick={() => setCount(count + 1)}>+1</button>
    </div>
  );
}

2. useEffect — побочные эффекты

// Запуск при монтировании
useEffect(() => {
  fetchData();
}, []);

// Запуск при изменении зависимости
useEffect(() => {
  const subscription = subscribe(userId);
  return () => subscription.unsubscribe();
}, [userId]);

// Запуск после каждого рендера
useEffect(() => {
  document.title = `Вы нажали ${count} раз`;
});

3. useContext — доступ к Context

const ThemeContext = createContext<'light' | 'dark'>('light');

function MyComponent() {
  const theme = useContext(ThemeContext);
  return <div className={theme}>Контент</div>;
}

4. useReducer — сложное состояние

type Action = { type: 'ADD'; payload: number } | { type: 'RESET' };
type State = { count: number };

function reducer(state: State, action: Action): State {
  switch (action.type) {
    case 'ADD':
      return { count: state.count + action.payload };
    case 'RESET':
      return { count: 0 };
  }
}

function Counter() {
  const [state, dispatch] = useReducer(reducer, { count: 0 });
  
  return (
    <div>
      <p>{state.count}</p>
      <button onClick={() => dispatch({ type: 'ADD', payload: 1 })}>
        +1
      </button>
    </div>
  );
}

5. useCallback — стабилизация функций

const handleClick = useCallback(() => {
  doSomething(a, b);
}, [a, b]);

// Или с useCallback и зависимостями
const memoizedCallback = useCallback(
  (x: number) => x * 2,
  []
);

6. useMemo — мемоизация значений

const expensiveValue = useMemo(() => {
  return computeExpensiveValue(a, b);
}, [a, b]);

// Пример: вычисление отфильтрованного списка
const filteredUsers = useMemo(() => {
  return users.filter(u => u.role === selectedRole);
}, [users, selectedRole]);

7. useRef — ссылки на DOM и значения

function TextInput() {
  const inputRef = useRef<HTMLInputElement>(null);
  
  const handleClick = () => {
    inputRef.current?.focus();
  };
  
  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>Фокус на input</button>
    </>
  );
}

// Сохранение счетчика между рендерами
function Timer() {
  const countRef = useRef(0);
  
  useEffect(() => {
    const interval = setInterval(() => {
      countRef.current++;
    }, 1000);
    
    return () => clearInterval(interval);
  }, []);
}

8. useLayoutEffect — синхронные побочные эффекты

// Вычисляется ПОСЛЕ рендера, но ДО отображения на экране
useLayoutEffect(() => {
  const height = element.clientHeight;
  setPosition(height);
}, []);

9. useDebugValue — отладка кастомных hooks

function useCustomHook() {
  const [value, setValue] = useState(0);
  
  useDebugValue(value > 10 ? 'High' : 'Low');
  
  return [value, setValue];
}

10. useId — генерация уникальных ID

function Form() {
  const emailId = useId();
  const passwordId = useId();
  
  return (
    <>
      <label htmlFor={emailId}>Email</label>
      <input id={emailId} type="email" />
      
      <label htmlFor={passwordId}>Пароль</label>
      <input id={passwordId} type="password" />
    </>
  );
}

11. useTransition — управление переходами

function SearchUsers() {
  const [input, setInput] = useState('');
  const [results, setResults] = useState<User[]>([]);
  const [isPending, startTransition] = useTransition();
  
  const handleSearch = (value: string) => {
    setInput(value);
    startTransition(async () => {
      const data = await searchAPI(value);
      setResults(data);
    });
  };
  
  return (
    <div>
      <input value={input} onChange={(e) => handleSearch(e.target.value)} />
      {isPending && <p>Загрузка...</p>}
      <ul>
        {results.map(u => <li key={u.id}>{u.name}</li>)}
      </ul>
    </div>
  );
}

12. useDeferredValue — отложенное значение

function App() {
  const [input, setInput] = useState('');
  const deferredInput = useDeferredValue(input);
  
  return (
    <>
      <input value={input} onChange={(e) => setInput(e.target.value)} />
      <ExpensiveList query={deferredInput} />
    </>
  );
}

13. Кастомные Hooks

function useWindowSize() {
  const [size, setSize] = useState({
    width: window.innerWidth,
    height: window.innerHeight
  });
  
  useEffect(() => {
    const handleResize = () => {
      setSize({
        width: window.innerWidth,
        height: window.innerHeight
      });
    };
    
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);
  
  return size;
}

// Использование
function MyComponent() {
  const { width, height } = useWindowSize();
  return <div>Размер: {width}x{height}</div>;
}

14. useFetch — запросы к API

function useFetch<T>(url: string) {
  const [data, setData] = useState<T | null>(null);
  const [error, setError] = useState<Error | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  
  useEffect(() => {
    fetch(url)
      .then(res => res.json())
      .then(data => { setData(data); setIsLoading(false); })
      .catch(err => { setError(err); setIsLoading(false); });
  }, [url]);
  
  return { data, error, isLoading };
}

// Использование
function UsersList() {
  const { data: users, isLoading } = useFetch<User[]>('/api/users');
  return isLoading ? <p>Загрузка...</p> : <div>{/* render users */}</div>;
}

Таблица основных Hooks

HookНазначениеПример
useStateСостояниеconst [count, setCount] = useState(0)
useEffectПобочные эффектыuseEffect(() => {}, [deps])
useContextДоступ к Contextconst theme = useContext(ThemeContext)
useReducerСложное состояниеconst [state, dispatch] = useReducer(...)
useCallbackСтабилизация функцийconst fn = useCallback(() => {}, [deps])
useMemoМемоизацияconst val = useMemo(() => {}, [deps])
useRefСсылкиconst ref = useRef(null)
useLayoutEffectСинхронные эффектыuseLayoutEffect(() => {}, [])
useIdУникальные IDconst id = useId()
useTransitionУправление переходамиconst [isPending, startTransition] = useTransition()

Best Practices

  1. Не вызывай Hooks условно — всегда на верхнем уровне
  2. Указывай правильные зависимости в массиве deps
  3. Создавай кастомные Hooks для переиспользуемой логики
  4. Используй useCallback и useMemo для оптимизации производительности
  5. Комбинируй Hooks для создания сложной логики
Какие знаешь Hook? | PrepBro