如果状态发生变化,为什么React Hooks会更新所有子组件?

时间:2020-01-24 13:39:51

标签: reactjs react-hooks

请考虑以下示例:

// 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() documentation说:

useCallback将返回回显的回调版本,仅在其中一个依赖项已更改时才更改。当将回调传递给依赖引用相等的优化子组件以防止不必要的渲染时,这很有用

这是非常模棱两可的,但是似乎建议可以将组件配置为仅在其任何prop值更改时进行更新,并且不使用useCallback()意味着每次{{1 }}被调用,因此App()将始终更新。

由于它说“优化”的子组件,大概不是默认行为吗?但为什么?如果道具没有变化,为什么还要更新?通过Form“优化”组件的全部要点是否比“改变道具”更为轻松?

1 个答案:

答案 0 :(得分:0)

当您将状态(val)作为对useCallback()的依赖项传递时,val更改时会生成一个新函数。这将导致子组件重新呈现。

要跳过将val作为依赖项的需要,同时又想更新它时仍具有先前状态的值,请使用updater function

如果新状态是使用先前状态计算的,则可以传递一个 函数为setState。该函数将接收先前的值, 并返回更新的值。

示例:

const onClick = useCallback(
  (n: string) => {
    setVal(v => v + 1);
  },
  [],
);