React性能优化

React更新流程

image.png :::info

  1. 同层节点之间相互比较,不会跨节点比较
  2. 不同类型的节点,产生不同的树结构
  3. 可以通过key来指定哪些节点在不同的渲染下保持稳定
  • key应该是唯一的
  • key不要使用随机数
  • 使用index作为key,对于性能是没有优化的 :::

    shouldComponentUpdate

    1. shouldComponentUpdate(nextProps, nextState)
    2. if(this.state.message !== nextState.message) {
    3. return true
    4. }
    5. return false
    6. }
  • 返回值为true, 则需要调用render方法

  • 返回值为false, 不调用render方法
  • 默认返回true, 也就是只要state发生改变,就会调用render方法

    PureComponent

    :::info 调用!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)进行浅层比较 ::: ```javascript import React, { PureComponent } from ‘react’ class App extends PureComponent {

}

  1. <a name="zCynZ"></a>
  2. #### 高阶组件memo
  3. 函数式组件在props没有改变时,也是不希望重新渲染其DOM树结构,可是使用`**memo**`来包裹该组件
  4. ```javascript
  5. import { memo } from 'react'
  6. const Profile = memo(function(props) {
  7. return <h2>{props.message}</h2>
  8. })
  9. export default Profile

数据不可变的力量

  1. shouldComponentUpdate(nextProps,nextState) {
  2. if(nextState !== this.state) {
  3. return true
  4. }
  5. return false
  6. }
  1. // 新开辟一个books堆内存
  2. const books = [...this.state.books]
  3. books.push(newBook)
  4. this.setState({books})
  5. // 仍然为原来的堆内存
  6. this.state.books.push(newBook)

Ref的使用

获取ref

某些情况下,我们需要获取DOM,可以通过refs进行操作

  1. <h2 ref="str">Hello</h2>
  2. // 通过this.refs.str获取DOM元素

通过**this.ref.current**获取DOM实例或者类组件实例

  1. import React, { createRef } from 'react'
  2. this.titleRef = createRef()
  3. <h2 ref={this.titleRef}></h2>
  4. // 通过this.titleRef.current获取DOM
  1. constructor() {
  2. this.titleRef = null
  3. }
  4. <h2 ref={elementRef => { this.titleRef = elementRef }}></h2>
  5. // 通过this.titleRef获取DOM结构

可以通过**ref**获取组件实例

  1. import React, { PureComponent, createRef } from 'react'
  2. class HelloWorld extends React.PureComponent {
  3. test() {
  4. console.log('HelloWorld组件的test方法')
  5. }
  6. render() {
  7. return <h2>HelloWorld</h2>
  8. }
  9. }
  10. export class App extends PureComponent {
  11. constructor(props) {
  12. super(props)
  13. this.componentRef = createRef()
  14. }
  15. getComponent() {
  16. console.log(this.componentRef.current)
  17. this.componentRef.current.test()
  18. }
  19. render() {
  20. return (
  21. <div>
  22. <HelloWorld ref={this.componentRef}/>
  23. <button onClick={ e => this.getComponent()}>获取组件实例</button>
  24. </div>
  25. )
  26. }
  27. }
  28. export default App

forwordRef获取函数组件DOM

  1. import React, { PureComponent, createRef, forwardRef } from 'react'
  2. const HelloWorld = forwardRef(function(props, ref) {
  3. return (
  4. <div>
  5. <h1 ref={ref}>Hello World</h1>
  6. <p>哈哈哈</p>
  7. </div>
  8. )
  9. })
  10. export class App extends PureComponent {
  11. constructor() {
  12. super()
  13. this.hwRef = createRef()
  14. }
  15. getComponent() {
  16. console.log(this.hwRef.current) // <h1>Hello World</h1>
  17. }
  18. render() {
  19. return (
  20. <div>
  21. <HelloWorld ref={this.hwRef}/>
  22. <button onClick={e => this.getComponent()}>获取组件实例</button>
  23. </div>
  24. )
  25. }
  26. }
  27. export default App

受控组件与非受控组件

受控组件

  1. import React, { PureComponent } from 'react'
  2. export class App extends PureComponent {
  3. constructor() {
  4. super()
  5. this.state = {
  6. username: "nannan"
  7. }
  8. }
  9. inputChange(event) {
  10. // console.log("inputChange:", event.target.value)
  11. this.setState({ username: event.target.value })
  12. }
  13. render() {
  14. const { username } = this.state
  15. return (
  16. <div>
  17. {/* 受控组件 */}
  18. <input type="input" value={username} onChange={e => this.inputChange(e)}/>
  19. {/* 非受控组件 */}
  20. <input type="text" />
  21. <h2>username: {username}</h2>
  22. </div>
  23. )
  24. }
  25. }
  26. export default App
  1. handleSumbitClick(event) {
  2. event.preventDefault()
  3. }
  4. handleUsernameChange(event) {
  5. this.setState({
  6. username: event.target.value
  7. })
  8. }
  9. handleChange(event) {
  10. // const name = event.target.name
  11. this.setState({
  12. [event.target.name]: event.target.value
  13. })
  14. }
  15. // label标签的for转换为htmlFor
  16. <form onSubmit={e => this.handleSubmitClick(e)}>
  17. <input type="text" id="username" name="username" value={username}
  18. onChange={e => handleUsernameChange(e)}
  19. />
  20. <button type="submit">submit</button>
  21. </form>
  1. state= {
  2. isAgree: true
  3. }
  4. handleChange(event) {
  5. this.setState({
  6. isAgree: event.target.checked
  7. })
  8. }
  9. <input type="checkbox"
  10. checked={isAgree} id="agree"
  11. onChange={e => this.handleChange(e)}
  12. />
  1. state = {
  2. hobbies: [
  3. { value: 'sing', text: '唱', isChecked: false},
  4. { value: 'dance', text: '跳', isChecked: false},
  5. { value: 'rap', text: 'rap', isChecked: false},
  6. ]
  7. }
  8. handleHobbiesChange(event,index) {
  9. const hobbies = [...this.state.hobbies]
  10. hobbies[index].isChecked = event.target.checked
  11. this.setState({ hobbies })
  12. this.state.hobbies.filter(item => item.isChecked).map(item => item.value)
  1. state = {
  2. // fruit: '',
  3. fruit: ['orange']
  4. }
  5. handle FruitChange(event) {
  6. this.setState({
  7. fruit: event.target.value
  8. })
  9. // Array.from(可迭代对象,mapfn)
  10. const options = Array.from(event.target.selectOptions)
  11. const values = options.map(item => item.value)
  12. // Array.from(arguments)
  13. // const values2 = Array.from(event.target.selectOptions, item => item.value)
  14. this.setState({ fruit: values })
  15. }
  16. <select value={this.state.fruit} onChange={ e => this.handleFruitChange(e)} multiple>
  17. <option value="apple">苹果</option>
  18. <option value="orange">橘子</option>
  19. </select>

image.png

非受控组件

在非受控组件中通过**defaultValue**来设置默认值

<input type="text" defaultValue={defaultName} ref={this.nameRef} />

// console.log("获取结果:", this.nameRef.current.value)

高阶组件

高阶组件的定义

接收一个函数作为参数或者返回一个函数作为结果的函数叫做**高阶函数**
**高阶组件式参数为组件,返回值为新组件的函数**

function hoc(Cpn) {
  class newCpn extends PureComponent {
    state = {
      info: {
        name: 'zzf',
        age: 22
      }
    }
    render() {
      return <Cpn {...this.state.info}/>
    }

  // 组件的名称可以通过displayName来修改
  newCpn.displayName = 'newComponent'
  return newCpn
}

高阶组件在一些React第三方库中会非常常见:

  • Redux中的connect
  • ReactRouter中的withRouter

    高阶组件的使用场景

  • 增强props

  • context
  • 登录鉴权
    function loginAuth(OriginComponent) {
    return props => {
      const token = localStorage.getItem("token")
      if (token) {
        return <OriginComponent {...props}/>
      } else {
        return <h2>请先登录</h2>
      }
    }
    }
    

    Portals的使用

    ```javascript import { createPortal } from ‘react-dom’

{ createPortal(, document.querySelect(“#app”)) }

<a name="wdx2w"></a>
### Fragment
但是,如果我们需要在Fragment中添加key,那么就不能使用短语法
```jsx
<Fragment>
    <h2>content</h2>
</Fragment>


// <><h2>content</h2></>

StrictMode

StrictMode 是一个用来突出显示应用程序中潜在问题的工具:

  • 识别不安全的生命周期
  • 使用过时的**ref**API
  • 检查意外的副作用
  • 使用废弃的findDOMNode方法
  • 检查过时的**context**API
    <React.StrictMode></React.StrictMode>