【问题标题】:React DID NOT update components after update list state (by hook)更新列表状态后反应没有更新组件(通过钩子)
【发布时间】:2020-09-29 12:30:42
【问题描述】:

当使用 useState 挂钩存储对象列表时(例如 [{ a:1 }, { a:2 }]),如果我更改列表的元素(对象)的内容,请做出反应 DO NOT 更新组件。


例如在下面的代码中,

如果我按下第一个按钮,第一个 h1 组件的内容将为 24。但是即使我按下第一个按钮,第一个 h1 组件组件不要更新。

如果我在按下第一个按钮后按下第二个按钮,组件更新。

const [tempList, setTempList] = useState([
  { a: 1 },
  { a: 2 }
])


return (
  <div>
    {
      tempList.map((item, idx) => {
        return <h1>{item.a}</h1>
      })
    }
    <button onClick={() => {
      let temp = tempList;
      temp[0]['a'] = 24
      setTempList(temp)
    }}>modify list</button>
    <button onClick={() => {setTempList(...tempList, {a: 3})}}>insert list</button>
  </div>
)

已经使用了 useReducer 钩子。但这不是解决方案。 如何更新组件?

【问题讨论】:

    标签: javascript reactjs components react-hooks


    【解决方案1】:

    当状态或道具改变时,React 会重新渲染组件。并且只看状态的内存地址就判断状态发生了变化。

    在第一个按钮的回调中,通过声明变量temp,您只是创建了tempList 数组的浅表副本。因此,即使修改了第一个对象,数组的id也没有改变,react也不知道状态已经改变了。

    此外,通过在 setState 函数中放置回调,您始终可以对当前状态有新的引用:

    const [state, setState] = useState(0);
    setState(state+1) <-- the state can be stale
    setState(state=>state+1) <-- increment is guaranteed
    

    尝试构建另一个数组:

    <button onClick={()=>{
      setTempList(tempList=>tempList.map((item,ind)=>{
        if(ind===0){
          return {a:24};
        }
        else{
          return item;
        }
      })
    }}>modify list</button>
    

    您在第二个回调中出现语法错误。除了修复之外,我再次建议给setTempList 函数添加一个回调函数。

    <button onClick={() => {
      setTempList(tempList=>[...tempList, {a: 3}])
    }}>insert list</button>
    

    【讨论】:

      【解决方案2】:

      您似乎正在更新对象的相同引用而不是推送新对象。试试这个 -

      const [tempList, setTempList] = useState([
        { a: 1 },
        { a: 2 }
      ])
      
      
      return (
        <div>
          {
            tempList.map((item, idx) => {
              return <h1>{item.a}</h1>
            })
          }
          <button onClick={() => {
            let temp = [...tempList];
            temp[0] = { a: 24 };
            setTempList(temp)
          }}>modify list</button>
          <button onClick={() => {setTempList(...tempList, {a: 3})}}>insert list</button>
        </div>
      )
      

      【讨论】:

      • 哦,您使用 [...templist] 进行深度复制,例如 JSON.parse(JSON.stringfy(templist)) 深度复制后是否会重新渲染?我去做。 THX
      • 嗯.. 我无法理解“深拷贝”和“创建新对象”的区别。你能解释一下吗?如果你没有更多的时间,那没关系。 THX 太多了
      猜你喜欢
      • 2021-11-12
      • 2021-05-19
      • 2020-02-25
      • 1970-01-01
      • 1970-01-01
      • 2022-07-11
      • 1970-01-01
      • 2021-04-17
      • 1970-01-01
      相关资源
      最近更新 更多