useState 和 props 的变化

Posted

技术标签:

【中文标题】useState 和 props 的变化【英文标题】:useState and changes in the 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 的值仅用于安装组件时(仅限第一次)。 【参考方案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 时,它会返回一个包含两个值的数组:

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

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

(默认值是你传递给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 以更改道具为条件是管理此问题的最简单方法。

以上是关于useState 和 props 的变化的主要内容,如果未能解决你的问题,请参考以下文章

如何在另一个带有 props 的组件中使用 useState 函数?

如何在反应中使用带有useState钩子的回调[重复]

React Hook useState 的新功能返回未定义

无法在 React Material-UI 中的 useState 中设置值

useState 不在 axios 承诺中执行

使用 useState 在 React 组件之间传递值