在線源碼地址:https://github.com/facebook/react/blob/master/packages/react/src/ReactContext.jscss
兩種實現方式react
爲何要棄用舊的api?git
老的api對context的提供方下層全部組件影響太大了,它會致使它下層全部的組件(即使該組件在沒有更新的狀況下),它每次更新的狀況下,都會從新渲染github
demoapi
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> )
源碼app
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的值的 */ }
16版本之後提出的功能,其目標讓react總體渲染過程有一個優先級排比,並總體的渲染過程可以中斷,他就能夠進行一個任務的調度,更好的利用cpu性能。react可以讓咱們去區分一些優先級高低的任務,在進行一個react更新的過程當中,優先執行一些較高的任務。dom
<ConcurrentMode> <Parent /> </ConcurrentMode>
ConcurrentMode有一個特性,在一個子樹當中渲染了ConcurrentMode以後,它下面的全部節點產生的更新 都是一個低優先級的更新async
demoide
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的?後續慢慢深刻學習 */