ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

React 原理

2021-11-30 19:58:00  阅读:114  来源: 互联网

标签:渲染 number 更新 React state 组件 原理 setState


文章目录


React 原理

1. setState() 的说明

1.1 更新数据

  • setState() 是异步更新数据的(同学们是怎么理解异步的?谁能说一下你理解异步的模型)

  • 可以多次调用 setState() ,只会触发一次重新渲染

    this.state = { count: 1 }
    this.setState({
        count: this.state.count + 1
    })
    console.log(this.state.count) // 1
    

1.2 推荐语法

  • 推荐:使用 setState((state, props) => {}) 语法

  • 参数 state :表示最新的 state

  • 参数 props :表示最新的 props

    this.setState((state, props) => {  
        return {
            count: state.count + 1
        }
    })
    console.log(this.state.count) // 1
    

1.3 第二个参数

  • 场景:在状态更新(页面完成重新渲染)后立即执行某个操作

  • 语法:setState(updater, [callback])

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

2. JSX 语法的转化过程

  • JSX 仅仅是 createElement() 方法的语法糖(简化语法)
  • JSX 语法被 @babel/preset-react 插件编译为 createElement() 方法
  • React 元素:是一个对象,用来描述你希望在屏幕上看到的内容

在这里插入图片描述

3. 组件更新机制

  • setState() 的两个作用: 1. 修改 state 2. 更新组件(UI)
  • 过程:父组件重新渲染时,也会重新渲染子组件。但只会渲染当前组件子树(当前组件及其所有子组件)

在这里插入图片描述

4. 组件性能优化

4.1 减轻 state

  • 减轻 state:只存储跟组件渲染相关的数据(比如:count / 列表数据 / loading状态 等)

  • 注意:不用做渲染的数据不要放在state 中,比如定时器id等

  • 对于这种需要在多个方法中用到的数据,应该放在 this 中(组件实例上)

    class Hello extends Component {
        componentDidMount() {
            // timerId存储到this中,而不是state中
            this.timerId = setInterval(() => {}, 2000)
        }
        componentWillUnmount() {
            clearInterval(this.timerId)
        }
        render() { … }
    }
    

4.2 避免不必要的重新渲染

  • 组件更新机制:父组件更新会引起子组件也被更新

  • 问题:子组件没有任何变化时也会重新渲染

  • 如何避免不必要的重新渲染呢?

  • 解决方式:使用钩子函数shouldComponentUpdate(nextProps, nextState)

  • 作用:通过返回值决定该组件是否重新渲染,返回 true 表示重新渲染,false 表示不重新渲染

  • 触发时机:组件更新阶段,组件重新渲染(render)前执行(shouldComponentUpdate  render)

    class App extends Component {
        shouldComponentUpdate(nextProps, nextState) {
            // 根据条件,决定是否重新渲染组件
            return false
        }
        render() {…}
    }
    

4.3 纯组件

  • 纯组件:PureComponent 与 React.Component 功能相似

  • 区别:PureComponent 内部自动实现了shouldComponentUpdate 钩子,不需要手动比较

  • 原理:纯组件内部通过分别对比 前后两次 props 和 state 的值,来决定是否重新渲染组件

    class Hello extends React.PureComponent {  
        render() {
            return (
                <div>纯组件</div>
            )
        }
    }
    
  • 说明:纯组件内部的对比是 shallow compare(浅层对比)

  • 对于值类型来说:比较两个值是否相同(直接赋值即可)

    let number = 0
    let newNumber = number
    newNumber = 2
    console.log(number === newNumber) // false
    
    state = { number: 0 }
    setState({
        number: Math.floor(Math.random() * 3)
    })
    // PureComponent内部对比:
    最新的state.number === 上一次的state.number // false,重新渲染组件
    
  • 对于引用类型来说:只比较对象的引用(地址)是否相同

    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,不重新渲染组件
    

    注意:state 或 props 中属性值为引用类型时,应该创建新数据,不要直接修改原数据!

    // 正确!创建新数据
    const newObj = {...state.obj, number: 2}  
    setState({ obj: newObj })
    
    // 正确!创建新数据
    // 不要用数组的push / unshift 等直接修改当前数组的的方法
    // 而应该用 concat 或 slice 等这些返回新数组的方法
    this.setState({
        list: [...this.state.list, {新数据}]
    })
    

5. 虚拟 DOM 和 Diff 算法

  • React 更新视图的思想是:只要state 变化就重新渲染视图
  • 特点:思路非常清晰
  • 问题:组件中只有一个 DOM 元素需要更新时,也得把整个组件的内容重新渲染到页面中?
  • 理想状态:部分更新,只更新变化的地方。
  • 问题:React 是如何做到部分更新的? 虚拟 DOM 配合 Diff 算法
  • 虚拟 DOM:本质上就是一个 JS 对象,用来描述你希望在屏幕上看到的内容(UI)

在这里插入图片描述

执行过程

  1. 初次渲染时,React 会根据初始state(Model),创建一个虚拟 DOM 对象(树)。
  2. 根据虚拟 DOM 生成真正的 DOM,渲染到页面中。
  3. 当数据变化后(setState()),重新根据新的数据,创建新的虚拟DOM对象(树)。
  4. 与上一次得到的虚拟 DOM 对象,使用 Diff 算法 对比(找不同),得到需要更新的内容。
  5. 最终,React 只将变化的内容更新(patch)到 DOM 中,重新渲染到页面。

标签:渲染,number,更新,React,state,组件,原理,setState
来源: https://blog.csdn.net/web00_11/article/details/121640706

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有