77 createFiberFromOffscreen ,
88 OffscreenProps
99} from './fiber' ;
10- import { renderWithHooks } from './fiberHooks' ;
11- import { Lane } from './fiberLanes' ;
10+ import { bailoutHook , renderWithHooks } from './fiberHooks' ;
11+ import { Lane , NoLanes , includeSomeLanes } from './fiberLanes' ;
1212import { processUpdateQueue , UpdateQueue } from './updateQueue' ;
1313import {
1414 ContextProvider ,
@@ -17,6 +17,7 @@ import {
1717 HostComponent ,
1818 HostRoot ,
1919 HostText ,
20+ MemoComponent ,
2021 OffscreenComponent ,
2122 SuspenseComponent
2223} from './workTags' ;
@@ -27,11 +28,63 @@ import {
2728 Placement ,
2829 ChildDeletion
2930} from './fiberFlags' ;
30- import { pushProvider } from './fiberContext' ;
31+ import {
32+ prepareToReadContext ,
33+ propagateContextChange ,
34+ pushProvider
35+ } from './fiberContext' ;
3136import { pushSuspenseHandler } from './suspenseContext' ;
37+ import { cloneChildFibers } from './childFibers' ;
38+ import { shallowEqual } from 'shared/shallowEquals' ;
39+
40+ // 是否能命中bailout
41+ let didReceiveUpdate = false ;
42+
43+ export function markWipReceivedUpdate ( ) {
44+ didReceiveUpdate = true ;
45+ }
3246
3347// 递归中的递阶段
3448export const beginWork = ( wip : FiberNode , renderLane : Lane ) => {
49+ // bailout策略
50+ didReceiveUpdate = false ;
51+ const current = wip . alternate ;
52+
53+ if ( current !== null ) {
54+ const oldProps = current . memoizedProps ;
55+ const newProps = wip . pendingProps ;
56+ // 四要素~ props type
57+ // {num: 0, name: 'cpn2'}
58+ // {num: 0, name: 'cpn2'}
59+ if ( oldProps !== newProps || current . type !== wip . type ) {
60+ didReceiveUpdate = true ;
61+ } else {
62+ // state context
63+ const hasScheduledStateOrContext = checkScheduledUpdateOrContext (
64+ current ,
65+ renderLane
66+ ) ;
67+ if ( ! hasScheduledStateOrContext ) {
68+ // 四要素~ state context
69+ // 命中bailout
70+ didReceiveUpdate = false ;
71+
72+ switch ( wip . tag ) {
73+ case ContextProvider :
74+ const newValue = wip . memoizedProps . value ;
75+ const context = wip . type . _context ;
76+ pushProvider ( context , newValue ) ;
77+ break ;
78+ // TODO Suspense
79+ }
80+
81+ return bailouOnAlreadyFinishedWork ( wip , renderLane ) ;
82+ }
83+ }
84+ }
85+
86+ wip . lanes = NoLanes ;
87+
3588 // 比较,返回子fiberNode
3689 switch ( wip . tag ) {
3790 case HostRoot :
@@ -41,15 +94,17 @@ export const beginWork = (wip: FiberNode, renderLane: Lane) => {
4194 case HostText :
4295 return null ;
4396 case FunctionComponent :
44- return updateFunctionComponent ( wip , renderLane ) ;
97+ return updateFunctionComponent ( wip , wip . type , renderLane ) ;
4598 case Fragment :
4699 return updateFragment ( wip ) ;
47100 case ContextProvider :
48- return updateContextProvider ( wip ) ;
101+ return updateContextProvider ( wip , renderLane ) ;
49102 case SuspenseComponent :
50103 return updateSuspenseComponent ( wip ) ;
51104 case OffscreenComponent :
52105 return updateOffscreenComponent ( wip ) ;
106+ case MemoComponent :
107+ return updateMemoComponent ( wip , renderLane ) ;
53108 default :
54109 if ( __DEV__ ) {
55110 console . warn ( 'beginWork未实现的类型' ) ;
@@ -59,12 +114,80 @@ export const beginWork = (wip: FiberNode, renderLane: Lane) => {
59114 return null ;
60115} ;
61116
62- function updateContextProvider ( wip : FiberNode ) {
117+ function updateMemoComponent ( wip : FiberNode , renderLane : Lane ) {
118+ // bailout四要素
119+ // props浅比较
120+ const current = wip . alternate ;
121+ const nextProps = wip . pendingProps ;
122+ const Component = wip . type . type ;
123+
124+ if ( current !== null ) {
125+ const prevProps = current . memoizedProps ;
126+
127+ // 浅比较props
128+ if ( shallowEqual ( prevProps , nextProps ) && current . ref === wip . ref ) {
129+ didReceiveUpdate = false ;
130+ wip . pendingProps = prevProps ;
131+
132+ // state context
133+ if ( ! checkScheduledUpdateOrContext ( current , renderLane ) ) {
134+ // 满足四要素
135+ wip . lanes = current . lanes ;
136+ return bailouOnAlreadyFinishedWork ( wip , renderLane ) ;
137+ }
138+ }
139+ }
140+ return updateFunctionComponent ( wip , Component , renderLane ) ;
141+ }
142+
143+ function bailouOnAlreadyFinishedWork ( wip : FiberNode , renderLane : Lane ) {
144+ if ( ! includeSomeLanes ( wip . childLanes , renderLane ) ) {
145+ if ( __DEV__ ) {
146+ console . warn ( 'bailout整棵子树' , wip ) ;
147+ }
148+ return null ;
149+ }
150+
151+ if ( __DEV__ ) {
152+ console . warn ( 'bailout一个fiber' , wip ) ;
153+ }
154+ cloneChildFibers ( wip ) ;
155+ return wip . child ;
156+ }
157+
158+ function checkScheduledUpdateOrContext (
159+ current : FiberNode ,
160+ renderLane : Lane
161+ ) : boolean {
162+ const updateLanes = current . lanes ;
163+
164+ if ( includeSomeLanes ( updateLanes , renderLane ) ) {
165+ return true ;
166+ }
167+ return false ;
168+ }
169+
170+ function updateContextProvider ( wip : FiberNode , renderLane : Lane ) {
63171 const providerType = wip . type ;
64172 const context = providerType . _context ;
65173 const newProps = wip . pendingProps ;
174+ const oldProps = wip . memoizedProps ;
175+ const newValue = newProps . value ;
176+
177+ pushProvider ( context , newValue ) ;
178+
179+ if ( oldProps !== null ) {
180+ const oldValue = oldProps . value ;
66181
67- pushProvider ( context , newProps . value ) ;
182+ if (
183+ Object . is ( oldValue , newValue ) &&
184+ oldProps . children === newProps . children
185+ ) {
186+ return bailouOnAlreadyFinishedWork ( wip , renderLane ) ;
187+ } else {
188+ propagateContextChange ( wip , context , renderLane ) ;
189+ }
190+ }
68191
69192 const nextChildren = newProps . children ;
70193 reconcileChildren ( wip , nextChildren ) ;
@@ -77,8 +200,21 @@ function updateFragment(wip: FiberNode) {
77200 return wip . child ;
78201}
79202
80- function updateFunctionComponent ( wip : FiberNode , renderLane : Lane ) {
81- const nextChildren = renderWithHooks ( wip , renderLane ) ;
203+ function updateFunctionComponent (
204+ wip : FiberNode ,
205+ Component : FiberNode [ 'type' ] ,
206+ renderLane : Lane
207+ ) {
208+ prepareToReadContext ( wip , renderLane ) ;
209+ // render
210+ const nextChildren = renderWithHooks ( wip , Component , renderLane ) ;
211+
212+ const current = wip . alternate ;
213+ if ( current !== null && ! didReceiveUpdate ) {
214+ bailoutHook ( wip , renderLane ) ;
215+ return bailouOnAlreadyFinishedWork ( wip , renderLane ) ;
216+ }
217+
82218 reconcileChildren ( wip , nextChildren ) ;
83219 return wip . child ;
84220}
@@ -88,16 +224,24 @@ function updateHostRoot(wip: FiberNode, renderLane: Lane) {
88224 const updateQueue = wip . updateQueue as UpdateQueue < Element > ;
89225 const pending = updateQueue . shared . pending ;
90226 updateQueue . shared . pending = null ;
227+
228+ const prevChildren = wip . memoizedState ;
229+
91230 const { memoizedState } = processUpdateQueue ( baseState , pending , renderLane ) ;
92231 wip . memoizedState = memoizedState ;
93232
94233 const current = wip . alternate ;
95234 // 考虑RootDidNotComplete的情况,需要复用memoizedState
96235 if ( current !== null ) {
97- current . memoizedState = memoizedState ;
236+ if ( ! current . memoizedState ) {
237+ current . memoizedState = memoizedState ;
238+ }
98239 }
99240
100241 const nextChildren = wip . memoizedState ;
242+ if ( prevChildren === nextChildren ) {
243+ return bailouOnAlreadyFinishedWork ( wip , renderLane ) ;
244+ }
101245 reconcileChildren ( wip , nextChildren ) ;
102246 return wip . child ;
103247}
0 commit comments