05-组件化高级-state数据保持不可变性

22 阅读1分钟

指的是state或者props中数据是引用类型的情况下,在setState时候,必须改变最外层数据的引用,才能保证pureComponent能够重新render

原理

pureComponent中setState后,调用shouldComponentUpdate(nextProps,nextState,nextContext){shallowEqual(nextState, this.state)}

shouldComponentUpdate(nextProps,nextState,nextContext)
{
    shallowEqual(nextState, this.state)
    shallowEqual(nextProps, this.props)
}

demo

  • 添加新书籍,数组添加一项
  • 修改+1,数组项的count+1 image.png 粘贴代码,可忽略
import React, { PureComponent, Component } from 'react'

export class App extends PureComponent {
  constructor() {
    super()
    this.state = {
      message: 'hello world',
      books: [
        {
          name: '你知不知道的js',
          price: 99,
          count: 1
        },
        {
          name: '程序员之道',
          price: 10,
          count: 2
        },
        {
          name: 'react深入浅出',
          price: 88,
          count: 20
        },
        {
          name: 'vue深入浅出',
          price: 9,
          count: 4
        }
      ]
    }
  }
  addCount (index) {
    console.log('index', index)
    // this.state.books[index].count++
    // this.setState({
    //   books: this.state.books
    // })
    const newBooks = [...this.state.books]
    newBooks[index].count++
    this.setState({
      books: newBooks
    })

  }
  addNewBook () {
    const book = {
      name: 'angular高级设计',
      price: 9,
      count: 4
    }
    // 直接修改state,重新设置,pureComponents无法更新
    // this.state.books.push(book)
    // const newBokks =
    //   this.setState({
    //     books: this.state.books
    //   })
    const newBooks = [...this.state.books]
    newBooks.push(book)
    this.setState({
      books: newBooks
    })
  }
  // shouldComponentUpdate (nextProps, nextState) {
  // shallowEqual(nextProps, this.props)
  // shallowEqual(nextState, this.state)
  // }
  render () {
    const { books } = this.state
    return (
      <div>
        <h2>书籍列表</h2>
        <ul>
          {
            books.map((item, index) => {
              return (
                <li key={item.name}>name:{item.name}-price: {item.price}-count: {item.count} <button onClick={() => this.addCount(index)}>+1</button></li>
              )
            })
          }
        </ul>
        <button onClick={() => this.addNewBook()}>添加新书籍</button>
      </div>
    )
  }
}

export default App

setState后不会变化

添加数据,这样不会变化,因为purComponent主要关注外层books是否是原来的

// push
this.state.books.push(newBook)
this.setState({
    books: this.stae.books
})

//修改数组项
this.state.books[index].count++
this.setState({
    books: this.state.books
})

setState后会变化

// push
const newBooks = [...this.state.books] //新的引用地址
newBooks.push(newBook)
this.setState({
    books: newBooks
})
//修改数组项
const newBooks = [...this.state.books]
newBooks[index].count++
this.setState({
    books: newBooks
})

总结

  1. state中引用类型必须浅拷贝一份,用拷贝之后的变量setState才可以让PureComponent render
  2. 数组前拷贝[...arr]