Skip to content

Commit 62d4561

Browse files
committed
Host environment side-effects
This creates a new API for processing side-effects on the host environment. During initial reconciliation host instances are created during the time sliced periods. During updates there is an opportunity for the host to prepare something on the instance during the time slicing, and to determine whether there were any changes. The could be thrown away. At the commit phase, these changes are finally committed to the host instance.
1 parent a4b8beb commit 62d4561

File tree

5 files changed

+65
-13
lines changed

5 files changed

+65
-13
lines changed

src/renderers/noop/ReactNoop.js

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,20 +20,44 @@
2020
'use strict';
2121

2222
import type { Fiber } from 'ReactFiber';
23+
import type { HostChildren } from 'ReactFiberReconciler';
2324

2425
var ReactFiberReconciler = require('ReactFiberReconciler');
2526

2627
var scheduledHighPriCallback = null;
2728
var scheduledLowPriCallback = null;
2829

30+
type Props = { };
31+
type Instance = { id: number };
32+
33+
var instanceCounter = 0;
34+
2935
var NoopRenderer = ReactFiberReconciler({
3036

31-
createHostInstance() {
37+
createInstance(type : string, props : Props, children : HostChildren<Instance>) : Instance {
38+
console.log('Create instance #' + instanceCounter);
39+
return {
40+
id: instanceCounter++
41+
};
42+
},
43+
44+
prepareUpdate(instance : Instance, oldProps : Props, newProps : Props, children : HostChildren<Instance>) : boolean {
45+
console.log('Prepare for update on #' + instance.id);
46+
return true;
47+
},
3248

49+
commitUpdate(instance : Instance, oldProps : Props, newProps : Props, children : HostChildren<Instance>) : void {
50+
console.log('Commit update on #' + instance.id);
3351
},
52+
53+
deleteInstance(instance : Instance) : void {
54+
console.log('Delete #' + instance.id);
55+
},
56+
3457
scheduleHighPriCallback(callback) {
3558
scheduledHighPriCallback = callback;
3659
},
60+
3761
scheduleLowPriCallback(callback) {
3862
scheduledLowPriCallback = callback;
3963
},

src/renderers/shared/fiber/ReactFiber.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ type Instance = {
4848
type: any,
4949

5050
// The local state associated with this fiber.
51-
stateNode: ?Object,
51+
stateNode: any,
5252

5353
// Conceptual aliases
5454
// parent : Instance -> return The parent happens to be the same as the

src/renderers/shared/fiber/ReactFiberCommitWork.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ var {
2424

2525
module.exports = function<T, P, I>(config : HostConfig<T, P, I>) {
2626

27+
const commitUpdate = config.commitUpdate;
28+
2729
function commitWork(finishedWork : Fiber) : void {
2830
switch (finishedWork.tag) {
2931
case ClassComponent:
@@ -33,7 +35,17 @@ module.exports = function<T, P, I>(config : HostConfig<T, P, I>) {
3335
// TODO: Attach children to root container.
3436
return;
3537
case HostComponent:
36-
console.log('commit updates to host component', finishedWork.type);
38+
if (finishedWork.stateNode == null || !finishedWork.alternate) {
39+
throw new Error('This should only be done during updates.');
40+
}
41+
const children = finishedWork.output;
42+
const newProps = finishedWork.memoizedProps;
43+
// If we have an alternate, that means this is an update and we need to
44+
// schedule a side-effect to do the updates.
45+
const current = finishedWork.alternate;
46+
const oldProps = current.memoizedProps;
47+
const instance : I = finishedWork.stateNode;
48+
commitUpdate(instance, oldProps, newProps, children);
3749
return;
3850
default:
3951
throw new Error('This unit of work tag should not have side-effects.');

src/renderers/shared/fiber/ReactFiberCompleteWork.js

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
import type { ReactCoroutine } from 'ReactCoroutine';
1616
import type { Fiber } from 'ReactFiber';
1717
import type { HostConfig } from 'ReactFiberReconciler';
18-
1918
import type { ReifiedYield } from 'ReactReifiedYield';
2019

2120
var ReactChildFiber = require('ReactChildFiber');
@@ -33,6 +32,9 @@ var {
3332

3433
module.exports = function<T, P, I>(config : HostConfig<T, P, I>) {
3534

35+
const createInstance = config.createInstance;
36+
const prepareUpdate = config.prepareUpdate;
37+
3638
function markForPostEffect(workInProgress : Fiber) {
3739
// Schedule a side-effect on this fiber, after the children's side-effects.
3840
if (workInProgress.lastEffect) {
@@ -120,13 +122,24 @@ module.exports = function<T, P, I>(config : HostConfig<T, P, I>) {
120122
case HostContainer:
121123
return null;
122124
case HostComponent:
125+
console.log('/host component', workInProgress.type);
123126
transferOutput(workInProgress.child, workInProgress);
124-
if (workInProgress.alternate) {
127+
const children = workInProgress.output;
128+
const newProps = workInProgress.memoizedProps;
129+
if (workInProgress.alternate && workInProgress.stateNode != null) {
125130
// If we have an alternate, that means this is an update and we need to
126131
// schedule a side-effect to do the updates.
127-
markForPostEffect(workInProgress);
132+
const current = workInProgress.alternate;
133+
const oldProps = current.memoizedProps;
134+
const instance : I = workInProgress.stateNode;
135+
if (prepareUpdate(instance, oldProps, newProps, children)) {
136+
// This returns true if there was something to update.
137+
markForPostEffect(workInProgress);
138+
}
139+
} else {
140+
const instance = createInstance(workInProgress.type, newProps, children);
141+
workInProgress.stateNode = instance;
128142
}
129-
console.log('/host component', workInProgress.type);
130143
return null;
131144
case CoroutineComponent:
132145
console.log('/coroutine component', workInProgress.pendingProps.handler.name);

src/renderers/shared/fiber/ReactFiberReconciler.js

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,21 @@ var {
2222
LowPriority,
2323
} = require('ReactPriorityLevel');
2424

25-
type ReactHostElement<T, P> = {
26-
type: T,
27-
props: P
28-
};
29-
3025
type Deadline = {
3126
timeRemaining : () => number
3227
};
3328

29+
type HostChildNode<I> = { output: HostChildren<I>, sibling: ?HostChildNode<I> };
30+
31+
export type HostChildren<I> = null | void | I | HostChildNode<I>;
32+
3433
export type HostConfig<T, P, I> = {
3534

36-
createHostInstance(element : ReactHostElement<T, P>) : I,
35+
createInstance(type : T, props : P, children : HostChildren<I>) : I,
36+
prepareUpdate(instance : I, oldProps : P, newProps : P, children : HostChildren<I>) : bool,
37+
commitUpdate(instance : I, oldProps : P, newProps : P, children : HostChildren<I>) : void,
38+
deleteInstance(instance : I) : void,
39+
3740
scheduleHighPriCallback(callback : () => void) : void,
3841
scheduleLowPriCallback(callback : (deadline : Deadline) => void) : void
3942

0 commit comments

Comments
 (0)