1

react immutable 相关困惑

 2 years ago
source link: https://www.v2ex.com/t/848476
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

V2EX  ›  React

react immutable 相关困惑

  yukinotech · 14 小时 51 分钟前 · 708 次点击

主要困惑的内容在两个 onClick 事件里,一个对于 state 是 immutable 的,另一个不是,但是效果是相同的。疑惑的点在于

  1. 两种写法是否都可以,第一种写法会不会导致 bug(比如 react18 cm 模式下)
  2. 如果两个写法都可以,是不是说明 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 } ]

第 1 条附言  ·  3 小时 16 分钟前

1,2楼的回复应该是对的,我这补一下示例。Person1是PureComponent,Person是fc component,当直接传p.person时,按示例中的用法,p.person的引用对于2个props是没变的,PureComponent在这种情况下就不会刷新值。

这一方面说明确实和实际的用法有关,另一方面我觉得也可以说明react本身和immutable是没啥关系的

import React, { useState } from 'react'

class Person1 extends React.PureComponent {
  constructor(props) {
    super(props)
  }
  render() {
    return <div>{this.props.person.name}</div>
  }
}
function Person({ person }) {
  return <div>{person.name}</div>
}

function App() {
  let [p, setP] = useState({
    person: { name: 'jack', age: 18 },
  })

  const onClick1 = () => {
    let newState = { ...p }
    newState.person.name = 'kk'
    setP(newState)
  }

  return (
    <div className="App">
      <button onClick={onClick1}>add1</button>
      {/* <button onClick={onClick2}>add2</button> */}
      <Person person={p.person} />
      <Person1 person={p.person} />
    </div>
  )
}

export default App

第 2 条附言  ·  2 小时 48 分钟前

再补一条
class 中会有这个问题的是 PureComponent ,FC 中对标的应该就是 React.memo(),这下就对上了

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK