7
7
createFiberFromOffscreen ,
8
8
OffscreenProps
9
9
} 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' ;
12
12
import { processUpdateQueue , UpdateQueue } from './updateQueue' ;
13
13
import {
14
14
ContextProvider ,
@@ -17,6 +17,7 @@ import {
17
17
HostComponent ,
18
18
HostRoot ,
19
19
HostText ,
20
+ MemoComponent ,
20
21
OffscreenComponent ,
21
22
SuspenseComponent
22
23
} from './workTags' ;
@@ -27,11 +28,63 @@ import {
27
28
Placement ,
28
29
ChildDeletion
29
30
} from './fiberFlags' ;
30
- import { pushProvider } from './fiberContext' ;
31
+ import {
32
+ prepareToReadContext ,
33
+ propagateContextChange ,
34
+ pushProvider
35
+ } from './fiberContext' ;
31
36
import { 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
+ }
32
46
33
47
// 递归中的递阶段
34
48
export 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
+
35
88
// 比较,返回子fiberNode
36
89
switch ( wip . tag ) {
37
90
case HostRoot :
@@ -41,15 +94,17 @@ export const beginWork = (wip: FiberNode, renderLane: Lane) => {
41
94
case HostText :
42
95
return null ;
43
96
case FunctionComponent :
44
- return updateFunctionComponent ( wip , renderLane ) ;
97
+ return updateFunctionComponent ( wip , wip . type , renderLane ) ;
45
98
case Fragment :
46
99
return updateFragment ( wip ) ;
47
100
case ContextProvider :
48
- return updateContextProvider ( wip ) ;
101
+ return updateContextProvider ( wip , renderLane ) ;
49
102
case SuspenseComponent :
50
103
return updateSuspenseComponent ( wip ) ;
51
104
case OffscreenComponent :
52
105
return updateOffscreenComponent ( wip ) ;
106
+ case MemoComponent :
107
+ return updateMemoComponent ( wip , renderLane ) ;
53
108
default :
54
109
if ( __DEV__ ) {
55
110
console . warn ( 'beginWork未实现的类型' ) ;
@@ -59,12 +114,80 @@ export const beginWork = (wip: FiberNode, renderLane: Lane) => {
59
114
return null ;
60
115
} ;
61
116
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 ) {
63
171
const providerType = wip . type ;
64
172
const context = providerType . _context ;
65
173
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 ;
66
181
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
+ }
68
191
69
192
const nextChildren = newProps . children ;
70
193
reconcileChildren ( wip , nextChildren ) ;
@@ -77,8 +200,21 @@ function updateFragment(wip: FiberNode) {
77
200
return wip . child ;
78
201
}
79
202
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
+
82
218
reconcileChildren ( wip , nextChildren ) ;
83
219
return wip . child ;
84
220
}
@@ -88,16 +224,24 @@ function updateHostRoot(wip: FiberNode, renderLane: Lane) {
88
224
const updateQueue = wip . updateQueue as UpdateQueue < Element > ;
89
225
const pending = updateQueue . shared . pending ;
90
226
updateQueue . shared . pending = null ;
227
+
228
+ const prevChildren = wip . memoizedState ;
229
+
91
230
const { memoizedState } = processUpdateQueue ( baseState , pending , renderLane ) ;
92
231
wip . memoizedState = memoizedState ;
93
232
94
233
const current = wip . alternate ;
95
234
// 考虑RootDidNotComplete的情况,需要复用memoizedState
96
235
if ( current !== null ) {
97
- current . memoizedState = memoizedState ;
236
+ if ( ! current . memoizedState ) {
237
+ current . memoizedState = memoizedState ;
238
+ }
98
239
}
99
240
100
241
const nextChildren = wip . memoizedState ;
242
+ if ( prevChildren === nextChildren ) {
243
+ return bailouOnAlreadyFinishedWork ( wip , renderLane ) ;
244
+ }
101
245
reconcileChildren ( wip , nextChildren ) ;
102
246
return wip . child ;
103
247
}
0 commit comments