23
popContextProvider,
24
popTopLevelContextObject,
25
} = require('ReactFiberContext');
26
+var ReactFeatureFlags = require('ReactFeatureFlags');
27
var ReactTypeOfWork = require('ReactTypeOfWork');
28
var ReactTypeOfSideEffect = require('ReactTypeOfSideEffect');
29
var ReactFiberExpirationTime = require('ReactFiberExpirationTime');
45
46
var invariant = require('fbjs/lib/invariant');
47
47
-module.exports = function<T, P, I, TI, PI, C, CX, PL>(
48
- config: HostConfig<T, P, I, TI, PI, C, CX, PL>,
48
+module.exports = function<T, P, I, TI, PI, C, CC, CX, PL>(
49
+ config: HostConfig<T, P, I, TI, PI, C, CC, CX, PL>,
50
hostContext: HostContext<C, CX>,
51
hydrationContext: HydrationContext<C, CX>,
52
) {
56
appendInitialChild,
57
finalizeInitialChildren,
58
prepareUpdate,
59
+ mutation,
60
+ persistence,
61
} = config;
62
63
const {
164
// down its children. Instead, we'll get insertions from each child in
165
// the portal directly.
166
} else if (node.child !== null) {
167
+ node.child.return = node;
168
node = node.child;
169
continue;
170
}
177
}
178
node = node.return;
179
}
180
+ node.sibling.return = node.return;
181
node = node.sibling;
182
}
183
}
184
185
+ let updateHostContainer;
186
+ let updateHostComponent;
187
+ let updateHostText;
188
+ if (mutation) {
189
+ if (ReactFeatureFlags.enableMutatingReconciler) {
190
+ // Mutation mode
191
+ updateHostContainer = function(workInProgress: Fiber) {
192
+ // Noop
193
+ };
194
+ updateHostComponent = function(
195
+ current: Fiber,
196
+ workInProgress: Fiber,
197
+ updatePayload: null | PL,
198
+ type: T,
199
+ oldProps: P,
200
+ newProps: P,
201
+ rootContainerInstance: C,
202
+ ) {
203
+ // TODO: Type this specific to this type of component.
204
+ workInProgress.updateQueue = (updatePayload: any);
205
+ // If the update payload indicates that there is a change or if there
206
+ // is a new ref we mark this as an update. All the work is done in commitWork.
207
+ if (updatePayload) {
208
+ markUpdate(workInProgress);
209
+ }
210
+ };
211
+ updateHostText = function(
212
+ current: Fiber,
213
+ workInProgress: Fiber,
214
+ oldText: string,
215
+ newText: string,
216
+ ) {
217
+ // If the text differs, mark it as an update. All the work in done in commitWork.
218
+ if (oldText !== newText) {
219
+ markUpdate(workInProgress);
220
+ }
221
+ };
222
+ } else {
223
+ invariant(false, 'Mutating reconciler is disabled.');
224
+ }
225
+ } else if (persistence) {
226
+ if (ReactFeatureFlags.enablePersistentReconciler) {
227
+ // Persistent host tree mode
228
+ const {
229
+ cloneInstance,
230
+ createContainerChildSet,
231
+ appendChildToContainerChildSet,
232
+ finalizeContainerChildren,
233
+ } = persistence;
234
+
235
+ // An unfortunate fork of appendAllChildren because we have two different parent types.
236
+ const appendAllChildrenToContainer = function(
237
+ containerChildSet: CC,
238
+ workInProgress: Fiber,
239
+ ) {
240
+ // We only have the top Fiber that was created but we need recurse down its
241
+ // children to find all the terminal nodes.
242
+ let node = workInProgress.child;
243
+ while (node !== null) {
244
+ if (node.tag === HostComponent || node.tag === HostText) {
245
+ appendChildToContainerChildSet(containerChildSet, node.stateNode);
246
+ } else if (node.tag === HostPortal) {
247
+ // If we have a portal child, then we don't want to traverse
248
+ // down its children. Instead, we'll get insertions from each child in
249
+ // the portal directly.
250
+ } else if (node.child !== null) {
251
+ node.child.return = node;
252
+ node = node.child;
253
+ continue;
254
+ }
255
+ if (node === workInProgress) {
256
+ return;
257
+ }
258
+ while (node.sibling === null) {
259
+ if (node.return === null || node.return === workInProgress) {
260
+ return;
261
+ }
262
+ node = node.return;
263
+ }
264
+ node.sibling.return = node.return;
265
+ node = node.sibling;
266
+ }
267
+ };
268
+ updateHostContainer = function(workInProgress: Fiber) {
269
+ const portalOrRoot: {containerInfo: C, pendingChildren: CC} =
270
+ workInProgress.stateNode;
271
+ const childrenUnchanged = workInProgress.firstEffect === null;
272
+ if (childrenUnchanged) {
273
+ // No changes, just reuse the existing instance.
274
+ } else {
275
+ const container = portalOrRoot.containerInfo;
276
+ let newChildSet = createContainerChildSet(container);
277
+ if (finalizeContainerChildren(container, newChildSet)) {
278
+ markUpdate(workInProgress);
279
+ }
280
+ portalOrRoot.pendingChildren = newChildSet;
281
+ // If children might have changed, we have to add them all to the set.
282
+ appendAllChildrenToContainer(newChildSet, workInProgress);
283
+ // Schedule an update on the container to swap out the container.
284
+ markUpdate(workInProgress);
285
+ }
286
+ };
287
+ updateHostComponent = function(
288
+ current: Fiber,
289
+ workInProgress: Fiber,
290
+ updatePayload: null | PL,
291
+ type: T,
292
+ oldProps: P,
293
+ newProps: P,
294
+ rootContainerInstance: C,
295
+ ) {
296
+ // If there are no effects associated with this node, then none of our children had any updates.
297
+ // This guarantees that we can reuse all of them.
298
+ const childrenUnchanged = workInProgress.firstEffect === null;
299
+ const currentInstance = current.stateNode;
300
+ if (childrenUnchanged && updatePayload === null) {
301
+ // No changes, just reuse the existing instance.
302
+ // Note that this might release a previous clone.
303
+ workInProgress.stateNode = currentInstance;
304
+ } else {
305
+ let recyclableInstance = workInProgress.stateNode;
306
+ let newInstance = cloneInstance(
307
+ currentInstance,
308
+ updatePayload,
309
+ type,
310
+ oldProps,
311
+ newProps,
312
+ workInProgress,
313
+ childrenUnchanged,
314
+ recyclableInstance,
315
+ );
316
+ if (
317
+ finalizeInitialChildren(
318
+ newInstance,
319
+ type,
320
+ newProps,
321
+ rootContainerInstance,
322
+ )
323
+ ) {
324
+ markUpdate(workInProgress);
325
+ }
326
+ workInProgress.stateNode = newInstance;
327
+ if (childrenUnchanged) {
328
+ // If there are no other effects in this tree, we need to flag this node as having one.
329
+ // Even though we're not going to use it for anything.
330
+ // Otherwise parents won't know that there are new children to propagate upwards.
331
+ markUpdate(workInProgress);
332
+ } else {
333
+ // If children might have changed, we have to add them all to the set.
334
+ appendAllChildren(newInstance, workInProgress);
335
+ }
336
+ }
337
+ };
338
+ updateHostText = function(
339
+ current: Fiber,
340
+ workInProgress: Fiber,
341
+ oldText: string,
342
+ newText: string,
343
+ ) {
344
+ if (oldText !== newText) {
345
+ // If the text content differs, we'll create a new text instance for it.
346
+ const rootContainerInstance = getRootHostContainer();
347
+ const currentHostContext = getHostContext();
348
+ workInProgress.stateNode = createTextInstance(
349
+ newText,
350
+ rootContainerInstance,
351
+ currentHostContext,
352
+ workInProgress,
353
+ );
354
+ // We'll have to mark it as having an effect, even though we won't use the effect for anything.
355
+ // This lets the parents know that at least one of their children has changed.
356
+ markUpdate(workInProgress);
357
+ }
358
+ };
359
+ } else {
360
+ invariant(false, 'Persistent reconciler is disabled.');
361
+ }
362
+ } else {
363
+ if (ReactFeatureFlags.enableNoopReconciler) {
364
+ // No host operations
365
+ updateHostContainer = function(workInProgress: Fiber) {
366
+ // Noop
367
+ };
368
+ updateHostComponent = function(
369
+ current: Fiber,
370
+ workInProgress: Fiber,
371
+ updatePayload: null | PL,
372
+ type: T,
373
+ oldProps: P,
374
+ newProps: P,
375
+ rootContainerInstance: C,
376
+ ) {
377
+ // Noop
378
+ };
379
+ updateHostText = function(
380
+ current: Fiber,
381
+ workInProgress: Fiber,
382
+ oldText: string,
383
+ newText: string,
384
+ ) {
385
+ // Noop
386
+ };
387
+ } else {
388
+ invariant(false, 'Noop reconciler is disabled.');
389
+ }
390
+ }
391
+
392
function completeWork(
393
current: Fiber | null,
394
workInProgress: Fiber,
431
// TODO: Delete this when we delete isMounted and findDOMNode.
432
workInProgress.effectTag &= ~Placement;
433
}
434
+ updateHostContainer(workInProgress);
435
return null;
436
}
437
case HostComponent: {
457
currentHostContext,
458
);
459
247
- // TODO: Type this specific to this type of component.
248
- workInProgress.updateQueue = (updatePayload: any);
249
- // If the update payload indicates that there is a change or if there
250
- // is a new ref we mark this as an update.
251
- if (updatePayload) {
252
- markUpdate(workInProgress);
253
- }
460
+ updateHostComponent(
461
+ current,
462
+ workInProgress,
463
+ updatePayload,
464
+ type,
465
+ oldProps,
466
+ newProps,
467
+ rootContainerInstance,
468
+ );
469
+
470
if (current.ref !== workInProgress.ref) {
471
markRef(workInProgress);
472
}
541
const oldText = current.memoizedProps;
542
// If we have an alternate, that means this is an update and we need
543
// to schedule a side-effect to do the updates.
328
- if (oldText !== newText) {
329
- markUpdate(workInProgress);
330
- }
544
+ updateHostText(current, workInProgress, oldText, newText);
545
} else {
546
if (typeof newText !== 'string') {
547
invariant(
587
return null;
588
case HostPortal:
589
popHostContainer(workInProgress);
590
+ updateHostContainer(workInProgress);
591
return null;
592
// Error cases
593
case IndeterminateComponent: