42
43
const isArray = Array.isArray;
44
45
-function createSubsequentChild(
46
- returnFiber : Fiber,
47
- existingChild : ?Fiber,
48
- previousSibling : Fiber,
49
- newChildren,
50
- priority : PriorityLevel
51
-) : Fiber {
52
- if (typeof newChildren !== 'object' || newChildren === null) {
53
- return previousSibling;
54
- }
45
+function ChildReconciler(shouldClone) {
46
+
47
+ function createSubsequentChild(
48
+ returnFiber : Fiber,
49
+ existingChild : ?Fiber,
50
+ previousSibling : Fiber,
51
+ newChildren,
52
+ priority : PriorityLevel
53
+ ) : Fiber {
54
+ if (typeof newChildren !== 'object' || newChildren === null) {
55
+ return previousSibling;
56
+ }
57
56
- switch (newChildren.$$typeof) {
57
- case REACT_ELEMENT_TYPE: {
58
- const element = (newChildren : ReactElement<any>);
59
- if (existingChild &&
60
- element.type === existingChild.type &&
61
- element.key === existingChild.key) {
62
- // TODO: This is not sufficient since previous siblings could be new.
63
- // Will fix reconciliation properly later.
64
- const clone = cloneFiber(existingChild, priority);
65
- clone.pendingProps = element.props;
66
- clone.child = existingChild.child;
67
- clone.sibling = null;
68
- clone.return = returnFiber;
69
- previousSibling.sibling = clone;
70
- return clone;
58
+ switch (newChildren.$$typeof) {
59
+ case REACT_ELEMENT_TYPE: {
60
+ const element = (newChildren : ReactElement<any>);
61
+ if (existingChild &&
62
+ element.type === existingChild.type &&
63
+ element.key === existingChild.key) {
64
+ // TODO: This is not sufficient since previous siblings could be new.
65
+ // Will fix reconciliation properly later.
66
+ const clone = shouldClone ? cloneFiber(existingChild, priority) : existingChild;
67
+ if (!shouldClone) {
68
+ clone.pendingWorkPriority = priority;
69
+ }
70
+ clone.pendingProps = element.props;
71
+ clone.child = existingChild.child;
72
+ clone.sibling = null;
73
+ clone.return = returnFiber;
74
+ previousSibling.sibling = clone;
75
+ return clone;
76
+ }
77
+ const child = createFiberFromElement(element, priority);
78
+ previousSibling.sibling = child;
79
+ child.return = returnFiber;
80
+ return child;
81
}
72
- const child = createFiberFromElement(element, priority);
73
- previousSibling.sibling = child;
74
- child.return = returnFiber;
75
- return child;
76
- }
82
78
- case REACT_COROUTINE_TYPE: {
79
- const coroutine = (newChildren : ReactCoroutine);
80
- const child = createFiberFromCoroutine(coroutine, priority);
81
- previousSibling.sibling = child;
82
- child.return = returnFiber;
83
- return child;
84
- }
83
+ case REACT_COROUTINE_TYPE: {
84
+ const coroutine = (newChildren : ReactCoroutine);
85
+ const child = createFiberFromCoroutine(coroutine, priority);
86
+ previousSibling.sibling = child;
87
+ child.return = returnFiber;
88
+ return child;
89
+ }
90
86
- case REACT_YIELD_TYPE: {
87
- const yieldNode = (newChildren : ReactYield);
88
- const reifiedYield = createReifiedYield(yieldNode);
89
- const child = createFiberFromYield(yieldNode, priority);
90
- child.output = reifiedYield;
91
- previousSibling.sibling = child;
92
- child.return = returnFiber;
93
- return child;
91
+ case REACT_YIELD_TYPE: {
92
+ const yieldNode = (newChildren : ReactYield);
93
+ const reifiedYield = createReifiedYield(yieldNode);
94
+ const child = createFiberFromYield(yieldNode, priority);
95
+ child.output = reifiedYield;
96
+ previousSibling.sibling = child;
97
+ child.return = returnFiber;
98
+ return child;
99
+ }
100
}
95
- }
101
97
- if (isArray(newChildren)) {
98
- let prev : Fiber = previousSibling;
99
- let existing : ?Fiber = existingChild;
100
- for (var i = 0; i < newChildren.length; i++) {
101
- prev = createSubsequentChild(returnFiber, existing, prev, newChildren[i], priority);
102
- if (prev && existing) {
103
- // TODO: This is not correct because there could've been more
104
- // than one sibling consumed but I don't want to return a tuple.
105
- existing = existing.sibling;
102
+ if (isArray(newChildren)) {
103
+ let prev : Fiber = previousSibling;
104
+ let existing : ?Fiber = existingChild;
105
+ for (var i = 0; i < newChildren.length; i++) {
106
+ var nextExisting = existing && existing.sibling;
107
+ prev = createSubsequentChild(returnFiber, existing, prev, newChildren[i], priority);
108
+ if (prev && existing) {
109
+ // TODO: This is not correct because there could've been more
110
+ // than one sibling consumed but I don't want to return a tuple.
111
+ existing = nextExisting;
112
+ }
113
}
114
+ return prev;
115
+ } else {
116
+ // TODO: Throw for unknown children.
117
+ return previousSibling;
118
}
108
- return prev;
109
- } else {
110
- // TODO: Throw for unknown children.
111
- return previousSibling;
119
}
113
-}
120
115
-function createFirstChild(returnFiber, existingChild, newChildren, priority) {
116
- if (typeof newChildren !== 'object' || newChildren === null) {
117
- return null;
118
- }
121
+ function createFirstChild(returnFiber, existingChild, newChildren, priority) {
122
+ if (typeof newChildren !== 'object' || newChildren === null) {
123
+ return null;
124
+ }
125
120
- switch (newChildren.$$typeof) {
121
- case REACT_ELEMENT_TYPE: {
122
- const element = (newChildren : ReactElement<any>);
123
- if (existingChild &&
124
- element.type === existingChild.type &&
125
- element.key === existingChild.key) {
126
- // Get the clone of the existing fiber.
127
- const clone = cloneFiber(existingChild, priority);
128
- clone.pendingProps = element.props;
129
- clone.child = existingChild.child;
130
- clone.sibling = null;
131
- clone.return = returnFiber;
132
- return clone;
126
+ switch (newChildren.$$typeof) {
127
+ case REACT_ELEMENT_TYPE: {
128
+ const element = (newChildren : ReactElement<any>);
129
+ if (existingChild &&
130
+ element.type === existingChild.type &&
131
+ element.key === existingChild.key) {
132
+ // Get the clone of the existing fiber.
133
+ const clone = shouldClone ? cloneFiber(existingChild, priority) : existingChild;
134
+ if (!shouldClone) {
135
+ clone.pendingWorkPriority = priority;
136
+ }
137
+ clone.pendingProps = element.props;
138
+ clone.child = existingChild.child;
139
+ clone.sibling = null;
140
+ clone.return = returnFiber;
141
+ return clone;
142
+ }
143
+ const child = createFiberFromElement(element, priority);
144
+ child.return = returnFiber;
145
+ return child;
146
}
134
- const child = createFiberFromElement(element, priority);
135
- child.return = returnFiber;
136
- return child;
137
- }
147
139
- case REACT_COROUTINE_TYPE: {
140
- const coroutine = (newChildren : ReactCoroutine);
141
- const child = createFiberFromCoroutine(coroutine, priority);
142
- child.return = returnFiber;
143
- return child;
144
- }
148
+ case REACT_COROUTINE_TYPE: {
149
+ const coroutine = (newChildren : ReactCoroutine);
150
+ const child = createFiberFromCoroutine(coroutine, priority);
151
+ child.return = returnFiber;
152
+ return child;
153
+ }
154
146
- case REACT_YIELD_TYPE: {
147
- // A yield results in a fragment fiber whose output is the continuation.
148
- // TODO: When there is only a single child, we can optimize this to avoid
149
- // the fragment.
150
- const yieldNode = (newChildren : ReactYield);
151
- const reifiedYield = createReifiedYield(yieldNode);
152
- const child = createFiberFromYield(yieldNode, priority);
153
- child.output = reifiedYield;
154
- child.return = returnFiber;
155
- return child;
155
+ case REACT_YIELD_TYPE: {
156
+ // A yield results in a fragment fiber whose output is the continuation.
157
+ // TODO: When there is only a single child, we can optimize this to avoid
158
+ // the fragment.
159
+ const yieldNode = (newChildren : ReactYield);
160
+ const reifiedYield = createReifiedYield(yieldNode);
161
+ const child = createFiberFromYield(yieldNode, priority);
162
+ child.output = reifiedYield;
163
+ child.return = returnFiber;
164
+ return child;
165
+ }
166
}
157
- }
167
159
- if (isArray(newChildren)) {
160
- var first : ?Fiber = null;
161
- var prev : ?Fiber = null;
162
- var existing : ?Fiber = existingChild;
163
- for (var i = 0; i < newChildren.length; i++) {
164
- if (prev == null) {
165
- prev = createFirstChild(returnFiber, existing, newChildren[i], priority);
166
- first = prev;
167
- } else {
168
- prev = createSubsequentChild(returnFiber, existing, prev, newChildren[i], priority);
169
- }
170
- if (prev && existing) {
171
- // TODO: This is not correct because there could've been more
172
- // than one sibling consumed but I don't want to return a tuple.
173
- existing = existing.sibling;
168
+ if (isArray(newChildren)) {
169
+ var first : ?Fiber = null;
170
+ var prev : ?Fiber = null;
171
+ var existing : ?Fiber = existingChild;
172
+ for (var i = 0; i < newChildren.length; i++) {
173
+ var nextExisting = existing && existing.sibling;
174
+ if (prev == null) {
175
+ prev = createFirstChild(returnFiber, existing, newChildren[i], priority);
176
+ first = prev;
177
+ } else {
178
+ prev = createSubsequentChild(returnFiber, existing, prev, newChildren[i], priority);
179
+ }
180
+ if (prev && existing) {
181
+ // TODO: This is not correct because there could've been more
182
+ // than one sibling consumed but I don't want to return a tuple.
183
+ existing = nextExisting;
184
+ }
185
}
186
+ return first;
187
+ } else {
188
+ // TODO: Throw for unknown children.
189
+ return null;
190
}
176
- return first;
177
- } else {
178
- // TODO: Throw for unknown children.
179
- return null;
191
}
192
+
193
+ // TODO: This API won't work because we'll need to transfer the side-effects of
194
+ // unmounting children to the returnFiber.
195
+ function reconcileChildFibers(
196
+ returnFiber : Fiber,
197
+ currentFirstChild : ?Fiber,
198
+ newChildren : ReactNodeList,
199
+ priority : PriorityLevel
200
+ ) : ?Fiber {
201
+ return createFirstChild(returnFiber, currentFirstChild, newChildren, priority);
202
+ }
203
+
204
+ return reconcileChildFibers;
205
}
206
183
-// TODO: This API won't work because we'll need to transfer the side-effects of
184
-// unmounting children to the returnFiber.
185
-exports.reconcileChildFibers = function(
186
- returnFiber : Fiber,
187
- currentFirstChild : ?Fiber,
188
- newChildren : ReactNodeList,
189
- priority : PriorityLevel
190
-) : ?Fiber {
191
- return createFirstChild(returnFiber, currentFirstChild, newChildren, priority);
192
-};
207
+exports.reconcileChildFibers = ChildReconciler(true);
208
+
209
+exports.reconcileChildFibersInPlace = ChildReconciler(false);