主要困惑的内容在两个 onClick 事件里,一个对于 state 是 immutable 的,另一个不是,但是效果是相同的。疑惑的点在于
- 两种写法是否都可以,第一种写法会不会导致 bug(比如 react18 cm 模式下)
- 如果两个写法都可以,是不是说明 react 本身并不强依赖 state 的 immutable ,只需要让 newState!==oldState ,也就是引用改变(非 js 基础类型),然后 newState 丢到 setState 里面去 react 都能正常 render
import { useState } from "react"
function App() {
let [personList, setPersonList] = useState([{ name: "jack", age: 18 }])
const onClick1 = () => {
let newState = [...personList]
newState.push({ name: "kk", age: 1 })
// 这里相当于直接修改了 personList[0].name 上的值,对于 personList 这个 state 没有做到 immutable
newState[0].name = "ddddddd"
setPersonList(newState)
}
const onClick2 = () => {
setPersonList([
{
// 这里先复制一遍 personList[0],再复制,personList 这个 state 在过程中是只读的,是 immutable
...personList[0],
name: "ddddddd",
},
...personList.slice(1),
{ name: "kk", age: 1 },
])
}
return (
<div className="App">
<button onClick={onClick1}>add1</button>
<button onClick={onClick2}>add2</button>
{personList.map((item, index) => {
return <div key={index}>{item.name}</div>
})}
</div>
)
}
export default App
补充一下上述语境中 immutable 的定义,以常见的 immutable 库 immer 为例,可以看到执行函数,返回 new1 后,old 的值是不变的,这样可以认为 old 是 immutable 的
import { produce } from "immer"
const old = [{ name: "jack", age: 18 }]
const new1 = produce(old, (state) => {
state[0].name = "ddddddd"
state.push({ name: "kk", age: 1 })
})
console.log("原始值", old) // 原始值 [ { name: 'jack', age: 18 } ]
console.log("新值", new1) // 新值 [ { name: 'ddddddd', age: 18 }, { name: 'kk', age: 1 } ]