为 useState() 钩子字符串化对象以避免重新渲染是一种好习惯吗
Posted
技术标签:
【中文标题】为 useState() 钩子字符串化对象以避免重新渲染是一种好习惯吗【英文标题】:Is it good Practice to Stringify Object for useState() Hook To Avoid Re-Rendering 【发布时间】:2020-07-03 01:04:43 【问题描述】:根据this 和that 的问题,spread operator 似乎用于更新在useState
挂钩中管理的对象。
我创建了一个超级简单的例子,发现即使对象的内容没有改变,也会触发重新渲染(很明显,因为对象改变了):
import React from "react";
function useFriendStatus()
const [person, setPersonProps] = React.useState(name:'Mark',age:23);
React.useEffect(() =>
console.log("rerender");
const interval = setInterval(() =>
setPersonProps(...person); //simply set the object again -> no content changed
console.log('update');
, 1000);
return () => clearInterval(interval);
, [person]);
return person;
export default function App()
const person = useFriendStatus();
return <div className="App">Hello World: "" + person.name</div>;
在这里您可以看到我的分析器的屏幕截图,显示似乎触发了重新渲染(即使显示的名称没有改变):
我想知道这是否是一种“好习惯”,因为一切似乎都被重新渲染了。有时,您从 API 获得深度嵌套的对象并将它们分解为超级简单的非对象 userState
挂钩是不可能的。
字符串化不是更好吗?
import React from "react";
function useFriendStatus()
const [person, setPersonProps] = React.useState(JSON.stringify(name:'Mark',age:23));
React.useEffect(() =>
console.log("rerender");
const interval = setInterval(() =>
const personCopy=JSON.parse(person);
setPersonProps(JSON.stringify(...personCopy));
console.log('update');
, 1000);
return () => clearInterval(interval);
, [person]);
return person;
export default function App()
const person = JSON.parse(useFriendStatus());
return <div className="App">Hello World: "" + person.name</div>;
在实践中你是如何处理的?
【问题讨论】:
【参考方案1】:我创建了一个超级简单的例子,发现即使对象的内容没有改变,也会触发重新渲染(很明显,因为对象改变了)
它与对象的“内容”无关,您的组件会重新渲染,因为您创建了对象的浅表副本...person
(更改其引用)。
在渲染阶段,React 与之前的状态进行浅比较,以确定是否会发生渲染,而在 javascript 中, ===
始终为 false。
扩展运算符似乎用于更新在 useState 挂钩中管理的对象。
由于状态应该被视为immutable,因此通常使用扩展运算符进行浅拷贝。
"只有在对象的 name 属性发生变化时才应该重新渲染"
在调用setState
之前添加一个条件是很常见的:
React.useEffect(() =>
const newPerson = ...person ; // fetch from some source
// or check if person.name !== newPerson.name
if (!isEqual(person, newPerson))
setPerson(newPerson);
, [person]);
【讨论】:
我很清楚“为什么”会执行重新渲染,但我想知道“如何”阻止它...... @user3579222 React.memo 您的示例的预期行为是什么?使用 stringify 比较字符串与比较对象不同 只有在对象的 name 属性发生变化时才应该重新渲染 我正在更新答案以上是关于为 useState() 钩子字符串化对象以避免重新渲染是一种好习惯吗的主要内容,如果未能解决你的问题,请参考以下文章
使用 prevState 和 useState 钩子更新对象内部数组中的对象
React Native:如何从循环中获取值到钩子 useState