依赖于prevState 的setState 赋值方式(特别是格式为对象数组时)


在React 的useState hook里,当state的变化依赖于prevState时,使用setState 赋值时需要采用“传入函数”的方法。

(警告:此时直接赋值newState 可能被React 的优化算法折叠,而无法达到预期效果)

例:(传入函数的一种优良示例)

以例子中方式赋值的优点(对比一些别的方式):

1. 如下这样的赋值,React 无法感知zone 的存储变化,所以component re-render 都不会触发 

// error 错误示例!
setZone(prevZone => prevZone[*].clicked = !prevZone[*].clicked)

 2. 使用深拷贝改变prevZone 的存储指针,简单粗暴,但是性能和内存消耗比较大。(旧内存的所有存储地址全部变化,没有复用内存可言)

// 深拷贝
setZone(prevZone => {
  const cloneZone = _.cloneDeep(prevZone)
  cloneZone[*].clicked = !cloneZone[*].clicked
})

综上:

示例方式通过map方法,只改变最外层内存指针变化,以及在唯一需要新开内存的对象上重新开内存赋值。比较符合内存的合理使用。

import { useState } from 'react';

export default function App() {
  const [zone, setZone] = useState([
    { id: 1, clicked: false },
    { id: 2, clicked: false },
  ])

  const toggleCircle = id => {
    setZone(prevZone => {
      return prevZone.map(item => item.id === id ? { ...item, clicked: !item.clicked } : item)
    })
  }

  return (
    
{zone.map(item => ( <li key={item.id} onClick={() => toggleCircle(item.id)} > {item.id} ))}
) }