useState 和 props 的变化
Posted
技术标签:
【中文标题】useState 和 props 的变化【英文标题】:useState and changes in the props 【发布时间】:2021-03-27 21:57:46 【问题描述】:我试图了解当您在一个组件中同时拥有 props
和 useState
时会发生什么。
我写了一个小例子,它有一个父组件用另一个子组件打印它的数字 -
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 函数?