> Как отобразить одновременно предыдущее и текущее значение пропса в React компоненте? (React)

Уровень: senior · Роль: frontend · Категория: Технические вопросы

Компании: Сбер

Стек: React

> Пример ответа

Короткий ответ

Для отображения предыдущего и текущего значения пропса в React компоненте используется хук useRef для хранения предыдущего значения и useEffect для его обновления после каждого рендера. Альтернативно можно применить пользовательский хук usePrevious, который инкапсулирует эту логику. Ключевой момент - обновление ref происходит в useEffect, то есть после того, как компонент отрендерился с новым пропсом.

Подробное объяснение

В React нет встроенного механизма для автоматического отслеживания предыдущих значений пропсов, так как компонент получает только текущие пропсы при каждом рендере. Однако, используя useRef, мы можем сохранить значение между рендерами без вызова повторного рендера. Схема работы:

  1. На каждом рендере текущее значение пропса доступно напрямую.
  2. В useEffect (или useLayoutEffect для синхронности) мы обновляем ref, записывая в него текущее значение.
  3. На следующем рендере ref содержит предыдущее значение, которое можно использовать для сравнения или отображения.

Важно понимать, что useEffect выполняется после рендера, поэтому ref всегда отстаёт на один рендер. Это гарантирует, что во время рендера мы видим предыдущее значение в ref и текущее - в пропсе.

На практике

Наиболее распространённый паттерн - создание пользовательского хука usePrevious, который принимает значение и возвращает его предыдущую версию. Этот хук универсален и может использоваться для любых пропсов или state. В компоненте мы просто вызываем const prevValue = usePrevious(value) и используем prevValue и value для отображения.

Если нужно отслеживать изменения нескольких пропсов, можно создать отдельные вызовы usePrevious для каждого. Для сложной логики сравнения (например, глубокое сравнение объектов) потребуется дополнительная обработка в useEffect.

Пример кода

JSX
import { useRef, useEffect } from 'react';
// Пользовательский хук
function usePrevious(value) {
const ref = useRef();
useEffect(() => {
ref.current = value;
}, [value]);
return ref.current;
}
// Компонент
function CounterDisplay({ count }) {
const prevCount = usePrevious(count);
return (
<div>
<p>Текущее значение: {count}</p>
<p>Предыдущее значение: {prevCount ?? 'нет предыдущего'}</p>
</div>
);
}

Как отвечать на собеседовании

Начни с ключевой идеи: useRef для хранения значения между рендерами и useEffect для его обновления после рендера. Объясни, почему нельзя использовать state (вызовет лишний рендер) или просто переменную (сбросится при ререндере). Упомяни, что хук usePrevious - это канонический паттерн в React, описанный в документации. Если спросят про useLayoutEffect, поясни, что он нужен для синхронного обновления ref до того, как браузер отрисует изменения, но для большинства случаев useEffect достаточно.

Что проверяет интервьюер

Интервьюер оценивает понимание жизненного цикла React компонента, разницы между ref и state, а также умение применять хуки для решения нетривиальных задач. Также проверяется знание того, что useEffect выполняется после рендера, и как это влияет на доступность предыдущего значения. Для senior уровня ожидается объяснение trade-off между useEffect и useLayoutEffect, а также возможные проблемы с замыканиями.

Типичные ошибки

  1. Использование useState для хранения предыдущего значения - это вызывает лишний рендер и может привести к бесконечному циклу.
  2. Обновление ref непосредственно в теле компонента (без useEffect) - ref будет содержать текущее значение, а не предыдущее, так как присваивание происходит до рендера.
  3. Забывание обработать случай первого рендера, когда предыдущего значения нет - нужно использовать undefined или null как начальное значение ref.
  4. Использование usePrevious с примитивами без указания зависимости в useEffect - если не указать [value], хук не будет отслеживать изменения.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью