08react基础-react原理

2021-09-06  本文已影响0人  东邪_黄药师

setState()更新数据

import React from 'react'
import ReactDOM from 'react-dom'
class App extends React.Component {
  state = {
    count: 1
  }

  handleClick = () => {
    // 此处,更新state
    // 注意:异步更新数据的!!!
    this.setState({
      count: this.state.count + 1
    })
    console.log('count:', this.state.count) // 1
    this.setState({
      count: this.state.count + 1 // 1 + 1
    })
    console.log('count:', this.state.count) // 1
  }
  render() {
    console.log('render')
    return (
      <div>
        <h1>计数器:{this.state.count}</h1>
        <button onClick={this.handleClick}>+1</button>
      </div>
    )
  }
}
ReactDOM.render(<App />, document.getElementById('root'))
执行结果.png

setState()推荐语法

this.setState((state, props) => {
return {
count: state.count + 1
  }
})
console.log(this.state.count) // 1
import React from 'react'
import ReactDOM from 'react-dom'

/* 
  setState() 推荐语法
*/

class App extends React.Component {
  state = {
    count: 1
  }

  handleClick = () => {
  

    // 推荐语法:
    // 注意:这种语法也是异步更新state的!
    this.setState((state, props) => {
      return {
        count: state.count + 1 // 1 + 1
      }
    })
    this.setState((state, props) => {
      console.log('第二次调用:', state)
      return {
        count: state.count + 1
      }
    })
    console.log('count:', this.state.count) // 1
  }

  render() {
    return (
      <div>
        <h1>计数器:{this.state.count}</h1>
        <button onClick={this.handleClick}>+1</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'))
执行结果.png

setState()第二个参数

this.setState(
(state, props) => {},
() => {console.log('这个回调函数会在状态更新后立即执行')}
)

例子:

this.setState(
(state, props) => {},
() => {
document.title = '更新state后的标题:' + this.state.count
   }
)

具体代码:

import React from 'react'
import ReactDOM from 'react-dom'

/* 
  setState() callback
*/

class App extends React.Component {
  state = {
    count: 1
  }

  handleClick = () => {
    this.setState(
      (state, props) => {
        return {
          count: state.count + 1
        }
      },
      // 状态更新后并且重新渲染后,立即执行:
      () => {
        console.log('状态更新完成:', this.state.count) // 2
        console.log(document.getElementById('title').innerText)
        document.title = '更新后的count为:' + this.state.count
      }
    )
    console.log(this.state.count) // 1
  }

  render() {
    return (
      <div>
        <h1 id="title">计数器:{this.state.count}</h1>
        <button onClick={this.handleClick}>+1</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'))

JSX语法的转化过程

image.png

组件更新机制

import React from 'react'
import ReactDOM from 'react-dom'

/* 
  组件更新机制
*/

import './index.css'

// 根组件
class App extends React.Component {
  state = {
    color: '#369'
  }

  getColor() {
    return Math.floor(Math.random() * 256)
  }

  changeBG = () => {
    this.setState(() => {
      return {
        color: `rgb(${this.getColor()}, ${this.getColor()}, ${this.getColor()})`
      }
    })
  }

  render() {
    console.log('根组件')
    return (
      <div className="app" style={{ backgroundColor: this.state.color }}>
        <button onClick={this.changeBG}>根组件 - 切换颜色状态</button>
        <div className="app-wrapper">
          <Parent1 />
          <Parent2 />
        </div>
      </div>
    )
  }
}

// ------------------------左侧---------------------------

class Parent1 extends React.Component {
  state = {
    count: 0
  }

  handleClick = () => {
    this.setState(state => ({ count: state.count + 1 }))
  }
  render() {
    console.log('左侧父组件')
    return (
      <div className="parent">
        <h2>
          左侧 - 父组件1
          <button onClick={this.handleClick}>点我({this.state.count})</button>
        </h2>
        <div className="parent-wrapper">
          <Child1 />
          <Child2 />
        </div>
      </div>
    )
  }
}

class Child1 extends React.Component {
  render() {
    console.log('左侧子组件 - 1')
    return <div className="child">子组件1-1</div>
  }
}
class Child2 extends React.Component {
  render() {
    console.log('左侧子组件 - 2')
    return <div className="child">子组件1-2</div>
  }
}

// ------------------------右侧---------------------------

class Parent2 extends React.Component {
  state = {
    count: 0
  }

  handleClick = () => {
    this.setState(state => ({ count: state.count + 1 }))
  }

  render() {
    console.log('右侧父组件')
    return (
      <div className="parent">
        <h2>
          右侧 - 父组件2
          <button onClick={this.handleClick}>点我({this.state.count})</button>
        </h2>
        <div className="parent-wrapper">
          <Child3 />
          <Child4 />
        </div>
      </div>
    )
  }
}

class Child3 extends React.Component {
  render() {
    console.log('右侧子组件 - 1')
    return <div className="child">子组件2-1</div>
  }
}
class Child4 extends React.Component {
  render() {
    console.log('右侧子组件 - 2')
    return <div className="child">子组件2-2 </div>
  }
}

ReactDOM.render(<App />, document.getElementById('root'))
更新子组件时.png
更新根组件时..png

组件性能优化

class Hello extends Component {
componentDidMount() {
// timerId存储到this中,而不是state中
this.timerId = setInterval(() => {}, 2000)
  }
componentWillUnmount() {
clearInterval(this.timerId)
   }
render() { … }
}
class Hello extends Component {
shouldComponentUpdate() {
// 根据条件,决定是否重新渲染组件
return false
}
render() {…}
}

随机数案例 如果随机获取的数值和之上一次一样不更新组件否则就更新

import React from 'react'
import ReactDOM from 'react-dom'

/* 
  组件性能优化:
*/

// 生成随机数
class App extends React.Component {
  state = {
    number: 0
  }

  handleClick = () => {
    this.setState(() => {
      return {
        number: 1
      }
    })
  }

  // 因为两次生成的随机数可能相同,如果相同,此时,不需要重新渲染
  shouldComponentUpdate(nextProps, nextState) {
    console.log('最新状态:', nextState, ', 当前状态:', this.state)

    return nextState.number !== this.state.number

    // if (nextState.number !== this.state.number) {
    //   return true
    // }
    // return false

    // if (nextState.number === this.state.number) {
    //   return false
    // }
    // return true
  }

  render() {
    console.log('render')
    return (
      <div>
        <h1>随机数:{this.state.number}</h1>
        <button onClick={this.handleClick}>重新生成</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'))
import React from 'react'
import ReactDOM from 'react-dom'

/* 
  组件性能优化:
*/

// 生成随机数
class App extends React.Component {
  state = {
    number: 0
  }

  handleClick = () => {
    this.setState(() => {
      return {
        number: Math.floor(Math.random() * 3)
      }
    })
  }

  // 因为两次生成的随机数可能相同,如果相同,此时,不需要重新渲染
  // shouldComponentUpdate(nextProps, nextState) {
  //   console.log('最新状态:', nextState, ', 当前状态:', this.state)
  //   return nextState.number !== this.state.number
  // }

  render() {
    // console.log('render')
    return (
      <div>
        <NumberBox number={this.state.number} />
        <button onClick={this.handleClick}>重新生成</button>
      </div>
    )
  }
}

class NumberBox extends React.Component {
  shouldComponentUpdate(nextProps) {
    console.log('最新props:', nextProps, ', 当前props:', this.props)
    // 如果前后两次的number值相同,就返回false,不更新组件
    return nextProps.number !== this.props.number

    // if (nextProps.number === this.props.number) {
    //   return false
    // }
    // return true
  }
  render() {
    console.log('子组件中的render')
    return <h1>随机数:{this.props.number}</h1>
  }
}

ReactDOM.render(<App />, document.getElementById('root'))

纯组件

作用以及使用

class Hello extends React.PureComponent {
render() {
return (
<div>纯组件</div>
     )
  }
}
const obj = { number: 0 }
const newObj = obj
newObj.number = 2
console.log(newObj === obj) // true
state = { obj: { number: 0 } }
// 错误做法
state.obj.number = 2
setState({ obj: state.obj })
// PureComponent内部比较:
最新的state.obj === 上一次的state.obj // true,不重新渲染组件
// 正确!创建新数据
const newObj = {...state.obj, number: 2}
setState({ obj: newObj })
// 正确!创建新数据
// 不要用数组的push / unshift 等直接修改当前数组的的方法
// 而应该用 concat 或 slice 等这些返回新数组的方法
this.setState({
list: [...this.state.list, {新数据}]
})

案例:

import React from 'react'
import ReactDOM from 'react-dom'

/* 
  组件性能优化:
*/

// 引用类型:
const obj = { number: 0 }
const newObj = obj
newObj.number = 2
console.log(newObj === obj) // true

// 生成随机数
class App extends React.PureComponent {
  state = {
    obj: {
      number: 0
    }
  }

  handleClick = () => {
    // 正确做法:创建新对象
    const newObj = { ...this.state.obj, number: Math.floor(Math.random() * 3) }
    this.setState(() => {
      return {
        obj: newObj
      }
    })

    // 错误演示:直接修改原始对象中属性的值
    /* const newObj = this.state.obj
    newObj.number = Math.floor(Math.random() * 3)

    this.setState(() => {
      return {
        obj: newObj
      }
    }) */
  }

  render() {
    console.log('父组件重新render')
    return (
      <div>
        <h1>随机数:{this.state.obj.number}</h1>
        <button onClick={this.handleClick}>重新生成</button>
      </div>
    )
  }
}

ReactDOM.render(<App />, document.getElementById('root'))

虚拟 DOM 和 Diff 算法

虚拟DOM

虚拟 DOM:本质上就是一个 JS 对象,用来描述你希望在屏幕上看到的内容(UI)。


image.png

Diff算法

执行过程

image.png

代码演示:

import React from 'react'
import ReactDOM from 'react-dom'

/* 
  虚拟DOM 和 Diff算法
*/

// 生成随机数
class App extends React.PureComponent {
  state = {
    number: 0
  }

  handleClick = () => {
    this.setState(() => {
      return {
        number: Math.floor(Math.random() * 2)
      }
    })
  }

  // render方法调用并不意味着浏览器中的重新渲染!!!
  // render方法调用仅仅说明要进行diff
  render() {
    const el = (
      <div>
        <h1>随机数:</h1>
        <p>{this.state.number}</p>
        <button onClick={this.handleClick}>重新生成</button>
      </div>
    )
    console.log(el)

    return el
  }
}

ReactDOM.render(<App />, document.getElementById('root'))
image.png
上一篇下一篇

猜你喜欢

热点阅读