zoukankan      html  css  js  c++  java
  • 【React源码解读】Context && ConcurrentMode

    context

    在线源码地址:https://github.com/facebook/react/blob/master/packages/react/src/ReactContext.js

    两种实现方式

    • childContextType (17版本将被废弃)
    • createContext (16版本更新)

    为什么要弃用旧的api?

    老的api对context的提供方下层所有组件影响太大了,它会导致它下层所有的组件(即便该组件在没有更新的情况下),它每次更新的情况下,都会重新渲染

    demo

    import React from 'react'
    import PropTypes from 'prop-types'
    
    const { Provider, Consumer } = React.createContext('default')
    
    class Parent extends React.Component {
      state = {
        childContext: '123',
        newContext: '456',
      }
    
      getChildContext() {
        return { value: this.state.childContext, a: 'aaaaa' }
      }
    
      render() {
        return (
          <>
            <div>
              <label>childContext:</label>
              <input
                type="text"
                value={this.state.childContext}
                onChange={e => this.setState({ childContext: e.target.value })}
              />
            </div>
            <div>
              <label>newContext:</label>
              <input
                type="text"
                value={this.state.newContext}
                onChange={e => this.setState({ newContext: e.target.value })}
              />
            </div>
            <Provider value={this.state.newContext}>{this.props.children}</Provider>
          </>
        )
      }
    }
    
    class Parent2 extends React.Component {
      // { value: this.state.childContext, a: 'bbbbb' }
      getChildContext() {
        return { a: 'bbbbb' }
      }
    
      render() {
        return this.props.children
      }
    }
    
    function Child1(props, context) {
      console.log(context)
      return <Consumer>{value => <p>newContext: {value}</p>}</Consumer>
    }
    
    Child1.contextTypes = {
      value: PropTypes.string,
    }
    
    class Child2 extends React.Component {
      render() {
        return (
          <p>
            childContext: {this.context.value} {this.context.a}
          </p>
        )
      }
    }
    
    // Child2.contextType = Consumer
    
    Child2.contextTypes = { // 通过这种方式,告诉react在渲染过程中,Child2组件希望去获取它的父层组件中所有传递的context中的某几个
      value: PropTypes.string,
      a: PropTypes.string,
    }
    
    Parent.childContextTypes = { // 声明传递给子组件的context
      value: PropTypes.string,
      a: PropTypes.string,
    }
    
    Parent2.childContextTypes = { 
      a: PropTypes.string,
    }
    
    export default () => (
      <Parent>
        <Parent2>
          <Child1 />
          <Child2 />
        </Parent2>
      </Parent>
    )
    
    

    源码

    export function createContext<T>(
      defaultValue: T, 
      calculateChangedBits: ?(a: T, b: T) => number,
    ) {
        /**
        calculateChangedBits: 一个方法,用来计算新老context变化
        
        */
    
        const context: ReactContext<T> = {
            $$typeof: REACT_CONTEXT_TYPE,
            _calculateChangedBits: calculateChangedBits,
            
            _currentValue: defaultValue,
            _currentValue2: defaultValue,
           
            Provider: (null: any),
            Consumer: (null: any),
         };
         
         /**
         $$typeof: 与ReactElement的$$typeof不一样
         _currentValue和_currentValue2用处是一样的,只是用的地方不一样,比如不同的平台不一样
         _currentValue: 用来记录Prvoider上面提供的value有变化的情况下,就会更新到这个_currentValue上面,就是用来记录最新的context的值的
         
         */
    }
    
    
    

    ConcurrentMode

    16版本以后提出的功能,其目标让react整体渲染过程有一个优先级排比,并整体的渲染过程能够中断,他就可以进行一个任务的调度,更好的利用cpu性能。react能够让我们去区分一些优先级高低的任务,在进行一个react更新的过程中,优先执行一些较高的任务。

      <ConcurrentMode>
        <Parent />
      </ConcurrentMode>
    

    ConcurrentMode有一个特性,在一个子树当中渲染了ConcurrentMode之后,它下面的所有节点产生的更新 都是一个低优先级的更新

    demo

    import React, { ConcurrentMode } from 'react'
    import { flushSync } from 'react-dom' // 能够强制某一个更新操作的时候,使用一个优先级最高的更新
    
    import './index.css'
    
    class Parent extends React.Component {
      state = {
        async: true,
        num: 1,
        length: 2000,
      }
    
      componentDidMount() {
        this.interval = setInterval(() => {
          this.updateNum()
        }, 200)
      }
    
      componentWillUnmount() {
        // 别忘了清除interval
        if (this.interval) {
          clearInterval(this.interval)
        }
      }
    
      updateNum() {
        const newNum = this.state.num === 3 ? 0 : this.state.num + 1
        if (this.state.async) {
          this.setState({
            num: newNum,
          })
        } else {
          flushSync(() => {
            this.setState({
              num: newNum,
            })
          })
        }
      }
    
      render() {
        const children = []
    
        const { length, num, async } = this.state
    
        for (let i = 0; i < length; i++) {
          children.push(
            <div className="item" key={i}>
              {num}
            </div>
          )
        }
    
        return (
          <div className="main">
            async:{' '}
            <input
              type="checkbox"
              checked={async}
              onChange={() => flushSync(() => this.setState({ async: !async }))}
            />
            <div className="wrapper">{children}</div>
          </div>
        )
      }
    }
    
    
    export default () => (
      <ConcurrentMode>
        <Parent />
      </ConcurrentMode>
    )
    
    

    源码

    // React.js
    import {
      REACT_CONCURRENT_MODE_TYPE,
      REACT_FRAGMENT_TYPE,
      REACT_PROFILER_TYPE,
      REACT_STRICT_MODE_TYPE,
      REACT_SUSPENSE_TYPE,
    } from 'shared/ReactSymbols';
    ...
    
    if (enableStableConcurrentModeAPIs) {
      React.ConcurrentMode = REACT_CONCURRENT_MODE_TYPE;
      React.Profiler = REACT_PROFILER_TYPE;
    } else {
      React.unstable_ConcurrentMode = REACT_CONCURRENT_MODE_TYPE;
      React.unstable_Profiler = REACT_PROFILER_TYPE;
    }
    
    
    ...
    
    /** 
    发现ConcurrentMode竟然是一个常量,于是我们去shared/ReactSymbols下一睹
    */
    
    // ReactSymbols.js
    const hasSymbol = typeof Symbol === 'function' && Symbol.for;
    
    ...
    
    export const REACT_CONCURRENT_MODE_TYPE = hasSymbol
      ? Symbol.for('react.concurrent_mode')
      : 0xeacf;
      
    ...
    /**
    我们发现,ConcurrentMode组件就是一个Symbol,它也没有任何的属性
    
    留有疑问,它到底是如何承载chilren的?后续慢慢深入学习
    */
    
    
  • 相关阅读:
    PAT (Advanced Level) Practice 1100 Mars Numbers (20分)
    PAT (Advanced Level) Practice 1107 Social Clusters (30分) (并查集)
    PAT (Advanced Level) Practice 1105 Spiral Matrix (25分)
    PAT (Advanced Level) Practice 1104 Sum of Number Segments (20分)
    PAT (Advanced Level) Practice 1111 Online Map (30分) (两次迪杰斯特拉混合)
    PAT (Advanced Level) Practice 1110 Complete Binary Tree (25分) (完全二叉树的判断+分享致命婴幼儿错误)
    PAT (Advanced Level) Practice 1109 Group Photo (25分)
    PAT (Advanced Level) Practice 1108 Finding Average (20分)
    P6225 [eJOI2019]异或橙子 树状数组 异或 位运算
    P4124 [CQOI2016]手机号码 数位DP
  • 原文地址:https://www.cnblogs.com/fe-linjin/p/11722880.html
Copyright © 2011-2022 走看看