Использование ref для предотвращения частого изменения значения от useCallback

В разделе часто задаваемых вопросов Reach Hooks Как прочитать часто меняющееся значение из useCallback? вот пример:

function Form() {
  const [text, updateText] = useState('');
  const textRef = useRef();

  useEffect(() => {
    textRef.current = text; // Write it to the ref
  });

  const handleSubmit = useCallback(() => {
    const currentText = textRef.current; // Read it from the ref
    alert(currentText);
  }, [textRef]); // Don't recreate handleSubmit like [text] would do

  return (
    <>
      <input value={text} onChange={e => updateText(e.target.value)} />
      <ExpensiveTree onSubmit={handleSubmit} />
    </>
  );
}

Я был так сбит с толку:

  • Вместо того чтобы useCallback обновлял функцию каждый раз при изменении текста, этот код перемещает ее в textRef в useEffect. Но разве это не то же самое, потому что функция обратного вызова не меняется, но вам все еще нужен 1 шаг, чтобы обновить значение в useEffect?
  • Почему textRef находится в массиве зависимостей? Разве textRef не является ссылкой, которая не меняется между рендерами? Мы всегда получаем одну и ту же ссылку, разве это не будет похоже на ввод пустого массива?

person Thaitao    schedule 15.01.2021    source источник


Ответы (1)


вместо useCallback обновлять функцию каждый раз при изменении текста, этот код перемещает ее в textRef в useEffect, но это не то же самое, потому что функция обратного вызова не изменяется, но вам все равно нужен 1 шаг для обновления значения в useEffect?

При настройке useRef каждый рендер запускается повторно useEffect, но handleSubmit остается прежним. При нормальной настройке каждый рендер будет повторно запускаться useCallback, а handleSubmit будет новой ссылкой на новую функцию. Я понимаю, почему на первый взгляд это похоже на тот же объем работы.

Преимущества подхода ref заключаются в том, что другие повторные рендеринга происходят на основе повторного рендеринга Form. Каждый раз, когда значение text изменяется, родительский Form выполняет повторный рендеринг, а дочерний input повторно рендерит, поскольку он принимает text в качестве опоры. ExpensiveTree не выполняет повторную визуализацию, потому что его свойство handleSubmit поддерживает ту же ссылку. Конечно, название ExpensiveTree предназначено для того, чтобы сказать нам, что мы хотим минимизировать повторный рендеринг этого компонента, поскольку это требует больших вычислительных ресурсов.

person Linda Paiste    schedule 23.01.2021