16.6 提供的一個feature,在線源碼地址:https://github.com/facebook/react/blob/master/packages/react/src/React.jsreact
在一個Suspense組件,它下面渲染了一個或者多個異步的組件,有任何一個組件throw了一個promise以後,在這個promise的resolved以前,都會顯示fallback中的內容。git
也就是說,在一個Suspense組件中,有多個組件,它要等它裏面全部組件都resolved以後,纔會撤銷掉fallback中的內容github
demoapi
// suspense/index.js import React, { Suspense, lazy } from 'react' const LazyComp = lazy(() => import('./lazy.js')) let data = '' let promise = '' function requestData() { if (data) return data if (promise) throw promise promise = new Promise(resolve => { setTimeout(() => { data = 'Data resolved' resolve() }, 2000) }) throw promise } function SuspenseComp() { const data = requestData() return <p>{data}</p> } export default () => ( <Suspense fallback="loading data"> <SuspenseComp /> <LazyComp /> </Suspense> ) // suspense/lazy.js import React from 'react' export default () => <p>Lazy Comp</p>
源碼數組
// React.js ... Suspense: REACT_SUSPENSE_TYPE // 仍是一個常量 ...
// https://github.com/facebook/react/blob/master/packages/react/src/ReactLazy.js import type {LazyComponent, Thenable} from 'shared/ReactLazyComponent'; import {REACT_LAZY_TYPE} from 'shared/ReactSymbols'; export function lazy<T, R>(ctor: () => Thenable<T, R>): LazyComponent<T> { return { $$typeof: REACT_LAZY_TYPE, _ctor: ctor, // 傳進來的參數 // React uses these fields to store the result. _status: -1, // 用來記錄當前thenable這個對象處於的狀態。當渲染到lazy component狀態的時候,會調用這個ctor,而後返回一個thenable對象,通常來講是一個promise,處於pending狀態,-1 _result: null, // 用來記錄Thenable resolved以後返回的屬性,在lazy最終resolved出來的組件,放在裏面。後續咱們渲染lazy component的時候,直接拿result }; }
先看一個demopromise
import React from 'react' function ChildrenDemo(props) { console.log(props.children) // 若是React.Children.map 返回的是一個數組,它會繼續把它們展開成一維數組 [1, 1, 1, 2, 2, 2] console.log(React.Children.map(props.children, c => [c, [c, c]])) return props.children } export default () => ( <ChildrenDemo> <span>1</span> <span>2</span> </ChildrenDemo> )
在線源碼地址瀏覽器
https://github.com/facebook/react/blob/master/packages/react/src/ReactChildren.js(點擊進入)dom
圖解源碼流程異步
mapIntoWithKeyPrefixInternal性能
【它是一個大遞歸】,在此作了如下幾件事情:
1. 處理key 2. 在此作一個很是重要的事情,就是去context pool中去獲取一個context 3. traverseAllChildren 4. 後續全部流程完,會把這個context歸還
traverseAllChildren
在此作了如下幾件事情:
1. children爲null的狀況return 0 2. traverseAllChildrenImpl
traverseAllChildrenImpl
【它是一個小遞歸】,根據react element的type作了如下幾件事情:
mapSingleChildIntoContext
作了如下幾個事情
小結:源碼中運用了遞歸+資源池這樣一個概念去編寫相應邏輯。在此談下對象池,當一個方法多是一個常常要被調用的方法。若是該方法展開的比較多,聲明和釋放的對象多,這是一個很是須要性能的問題,尤爲是在瀏覽器計算的過程當中,可能須要去重複的去new 和delete一塊內存空間,避免內存計算形成的性能抖動,從而去節省一部分的開銷
16.6 feature 目的是給function component也提供一個相似pure component的功能
源碼
... export default function memo<Props>( type: React$ElementType, compare?: (oldProps: Props, newProps: Props) => boolean, ) { ... return { $$typeof: REACT_MEMO_TYPE, type, compare: compare === undefined ? null : compare, }; }
從上面來看,最終返回了一個$$typeof爲REACT_MEMO_TYPE的對象,真正的處理邏輯還須要在react-dom中學習
const functionComponent = () => { return <> <span>1</span> </> }
<> 實際上是React.Fragment
源碼
Fragment: REACT_FRAGMENT_TYPE // 依然是一個常量,實際處理邏輯須要在react-dom中查看對此類型的處理
提供一些過期api的提醒
源碼
StrictMode: REACT_STRICT_MODE_TYPE // 依然是個symbol
在ReactElement.js源碼中,實現了對element進行了clone的邏輯