Почему React Hooks обновляет все дочерние компоненты, если изменяется любое состояние? - PullRequest
0 голосов
/ 24 января 2020

Рассмотрим следующий пример:

// Form.tsx
import React from "react";

interface FormProps {
  name: string;
  onClick: (n: string) => void;
}

export function Form(props: FormProps) {
  console.log("Form rendered");
  return (
    <input type="button" onClick={() => props.onClick(props.name)} value={`Hello ${props.name}`}/>
  );
}

// App.tsx
import React, { useState, useCallback } from 'react';
import './App.css';
import { Form } from './Form';

interface AppState {
  val: number;
}

interface AppProps {
}

export function App(props: AppProps) {
  const [val, setVal] = useState(1);

  const onClick = useCallback(
    (n: string) => {
      console.log(val);
      setVal(val + 1);
    },
    [val],
  );

  return (
    <div>
      <p>Value: {val}</p>
      <Form name="foo" onClick={onClick}/>
    </div>
  );
}

Я передаю реквизит и обратный вызов компоненту Form. Когда вызывается обратный вызов, он обновляет состояние val. Это состояние не используется в элементе <Form>, но React по-прежнему повторно отображает его (Form rendered выводится на консоль).

Это кажется ненужным. useCallback() документация гласит:

useCallback вернет запомненную версию обратного вызова, которая изменяется только в случае изменения одной из зависимостей. Это полезно при передаче обратных вызовов оптимизированным дочерним компонентам, которые полагаются на равенство ссылок для предотвращения ненужных визуализаций.

Это довольно неоднозначно, но, похоже, предполагается, что компоненты можно настроить на обновление, только если какой-либо из их компонентов значения меняются, и если не использовать useCallback(), это означает, что новая функция будет создаваться каждый раз, когда вызывается App(), и, следовательно, Form будет всегда обновляться.

Поскольку он говорит «оптимизированные» дочерние компоненты, по-видимому, это не поведение по умолчанию? Но почему? Зачем вам обновляться, если ни один из реквизитов не изменился? Разве весь смысл «оптимизации» компонента с помощью shouldComponentUpdate заключается в том, что вы можете быть более расслабленным, чем «изменилась ли пропа?»

1 Ответ

0 голосов
/ 24 января 2020

Когда вы передаете состояние (val) в качестве зависимости useCallback(), новая функция генерируется при изменении val. Это заставляет дочерний компонент перерисовываться.

Чтобы пропустить необходимость включать val в качестве зависимости, сохраняя при этом значение предыдущего состояния, когда вы хотите обновить его, используйте функцию обновления :

Если новое состояние вычисляется с использованием предыдущего состояния, вы можете передать функцию setState. Функция получит предыдущее значение и вернет обновленное значение.

Пример:

const onClick = useCallback(
  (n: string) => {
    setVal(v => v + 1);
  },
  [],
); 
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...