【问题标题】:Is it good Practice to Stringify Object for useState() Hook To Avoid Re-Rendering为 useState() 钩子字符串化对象以避免重新渲染是一种好习惯吗
【发布时间】:2020-07-03 01:04:43
【问题描述】:

根据thisthat 的问题,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>;
}

在实践中你是如何处理的?

【问题讨论】:

    标签: javascript reactjs react-hooks


    【解决方案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 属性发生变化时才应该重新渲染
    • 我正在更新答案
    猜你喜欢
    • 2016-12-20
    • 2023-03-22
    • 2011-07-13
    • 2017-08-09
    • 1970-01-01
    • 1970-01-01
    • 2011-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多