【问题标题】:useState and changes in the propsuseState 和 props 的变化
【发布时间】:2021-03-27 21:57:46
【问题描述】:

我试图了解当您在一个组件中同时拥有 propsuseState 时会发生什么。

我写了一个小例子,它有一个父组件用另一个子组件打印它的数字 -

const MyNumbers = (props) => {
  const [numbers, setNumbers] = useState([...props.arr]);

  function changeNumbers() {
    setNumbers((nums) => [...nums.map(() => Math.floor(Math.random() * 10))]);
  }

  return (
    <div className="MyNumbers">
      <div>
        <button onClick={changeNumbers}>Chane numbers</button>
      </div>
      <div>
        {numbers.map((num, idx) => (
          <SingleNumber key={idx} num={num}></SingleNumber>
        ))}
      </div>
    </div>
  );
};
const SingleNumber = (props) => {
  const [num] = useState(props.num);
  useEffect(() => {
    console.log("useEffect called");
  });
  return <h3>The number is {num}</h3>;
};

Here is the above demo

SingleNumber 组件使用useState,正如您所见,单击“更改数字”操作不会更改子组件中的值。

但是当我编写几乎相同的代码但现在 SingleNumber 不使用 useState 时,然后单击“更改数字”会更改子组件中的所有值 (like in this demo)。

说一个带有useState 的函数组件只渲染一次,然后仅在状态更改时才更改,而props 更改时才更改,这是否正确?

【问题讨论】:

  • 组件每次都重新渲染。但是您基本上 缓存 本地状态中的值并一直输出该值。您传递给useState 的值仅用于安装组件时(仅限第一次)。

标签: javascript reactjs react-hooks use-state


【解决方案1】:

OFC 组件在 props 更改时“重新渲染”,SingleNumber 中的 useEffect 钩子向您展示每次都运行“渲染阶段”道具发生变化......每次渲染组件时都会运行效果。

const SingleNumber = (props) => {
  const [num] = useState(props.num);
  useEffect(() => {
    console.log("useEffect called"); // <-- logged each time the component renders
  });
  return <h3>The number is {num}</h3>;
};

如果您添加了对 props.num 的依赖并更新了本地状态(实际上不要这样做,这是反应中的反模式!),您将看到 UI 再次更新每次道具更新。

回答你的问题:

说一个带有useState的函数组件渲染是否正确 一次,然后仅在状态更改时才更改,但在 props 时不会更改 变了吗?

不,这在技术上是不正确的,如果“渲染”对您意味着严格反应渲染组件以计算差异,反应组件在状态或道具更新时重新渲染。是的,如果“渲染”更普遍地意味着您可以直观地看到 UI 更新。

【讨论】:

    【解决方案2】:

    当您调用useState 时,它会返回一个包含两个值的数组:

    1. 该状态位的当前值
    2. 更新状态的函数

    如果设置状态为默认值时没有当前值,则返回。

    (默认值是你传递给useState的参数)。


    如果您在示例中更改 props 的值,则组件会重新呈现。

    useState 返回该状态位的当前值。状态一个值,因此它不会对您传递给useState 的参数做任何事情。该值已更改并不重要。

    由于输出中没有其他任何更改,因此重新渲染的组件不会更新 DOM。

    【讨论】:

      【解决方案3】:

      说一个带有 useState 的函数组件只渲染一次,然后只在 state 改变而不是 props 改变时才改变,这是否正确?

      不,它会重新渲染,但不会提交更改。

      当父组件MyNumbers通过单击changeNumbers重新渲染时,默认情况下(除非使用React.memo)它的所有子组件(如SingleNumber)都会重新渲染。

      现在当SingleNumber 重新渲染时,请注意useState docs

      在初始渲染期间,返回的状态(state)与作为第一个参数(initialState)传递的值相同。

      你初始化了状态useState(props.num),但它只能通过调用setter函数来改变,因此状态num不会改变,因为你从来没有调用setter。

      但它如上所述在父渲染上重新渲染(注意useEffect 日志)。

      【讨论】:

        【解决方案4】:

        您不需要在SingleNumber 中使用useState

        因为useState 在渲染时只调用了一次。

        const SingleNumber = (props) => {
          // const [num] = useState(props.num);
          // useEffect(() => {
          //   console.log("useEffect called");
          // });
          return <h3>The number is {props.num}</h3>;
        };
        

        如果你想使用useState,你可以这样使用。

        const SingleNumber = (props) => {
           const [num, setNum] = useState(props.num);
           useEffect(() => {
             console.log("useEffect called");
             setNum(props.num);
        
           }, [props.num]);
          return <h3>The number is {num}</h3>;
        };
        

        【讨论】:

        • useEffect 以更改道具为条件是管理此问题的最简单方法。
        猜你喜欢
        • 2020-02-24
        • 2019-08-11
        • 2014-12-20
        • 2018-12-19
        • 2022-07-09
        • 1970-01-01
        • 2020-03-21
        • 1970-01-01
        • 2020-09-22
        相关资源
        最近更新 更多