React 原理


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 中,重新渲染到页面。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值