UNPKG

8.85 kBJavaScriptView Raw
1/**
2 * Copyright (c) 2013-present, Facebook, Inc.
3 *
4 * This source code is licensed under the MIT license found in the
5 * LICENSE file in the root directory of this source tree.
6 *
7 *
8 */
9
10'use strict';
11
12var REACT_ELEMENT_TYPE = require('./ReactElementSymbol');
13
14var _require = require('./ReactCoroutine'),
15 REACT_COROUTINE_TYPE = _require.REACT_COROUTINE_TYPE,
16 REACT_YIELD_TYPE = _require.REACT_YIELD_TYPE;
17
18var ReactFiber = require('./ReactFiber');
19var ReactReifiedYield = require('./ReactReifiedYield');
20
21var cloneFiber = ReactFiber.cloneFiber,
22 createFiberFromElement = ReactFiber.createFiberFromElement,
23 createFiberFromCoroutine = ReactFiber.createFiberFromCoroutine,
24 createFiberFromYield = ReactFiber.createFiberFromYield;
25var createReifiedYield = ReactReifiedYield.createReifiedYield;
26
27
28var isArray = Array.isArray;
29
30function ChildReconciler(shouldClone) {
31 function createSubsequentChild(returnFiber, existingChild, previousSibling, newChildren, priority) {
32 if (typeof newChildren !== 'object' || newChildren === null) {
33 return previousSibling;
34 }
35
36 switch (newChildren.$$typeof) {
37 case REACT_ELEMENT_TYPE:
38 {
39 var element = newChildren;
40 if (existingChild && element.type === existingChild.type && element.key === existingChild.key) {
41 // TODO: This is not sufficient since previous siblings could be new.
42 // Will fix reconciliation properly later.
43 var clone = shouldClone ? cloneFiber(existingChild, priority) : existingChild;
44 if (!shouldClone) {
45 // TODO: This might be lowering the priority of nested unfinished work.
46 clone.pendingWorkPriority = priority;
47 }
48 clone.pendingProps = element.props;
49 clone.sibling = null;
50 clone['return'] = returnFiber;
51 previousSibling.sibling = clone;
52 return clone;
53 }
54 var child = createFiberFromElement(element, priority);
55 previousSibling.sibling = child;
56 child['return'] = returnFiber;
57 return child;
58 }
59
60 case REACT_COROUTINE_TYPE:
61 {
62 var coroutine = newChildren;
63 var _child = createFiberFromCoroutine(coroutine, priority);
64 previousSibling.sibling = _child;
65 _child['return'] = returnFiber;
66 return _child;
67 }
68
69 case REACT_YIELD_TYPE:
70 {
71 var yieldNode = newChildren;
72 var reifiedYield = createReifiedYield(yieldNode);
73 var _child2 = createFiberFromYield(yieldNode, priority);
74 _child2.output = reifiedYield;
75 previousSibling.sibling = _child2;
76 _child2['return'] = returnFiber;
77 return _child2;
78 }
79 }
80
81 if (isArray(newChildren)) {
82 var prev = previousSibling;
83 var existing = existingChild;
84 for (var i = 0; i < newChildren.length; i++) {
85 var nextExisting = existing && existing.sibling;
86 prev = createSubsequentChild(returnFiber, existing, prev, newChildren[i], priority);
87 if (prev && existing) {
88 // TODO: This is not correct because there could've been more
89 // than one sibling consumed but I don't want to return a tuple.
90 existing = nextExisting;
91 }
92 }
93 return prev;
94 } else {
95 // TODO: Throw for unknown children.
96 return previousSibling;
97 }
98 }
99
100 function createFirstChild(returnFiber, existingChild, newChildren, priority) {
101 if (typeof newChildren !== 'object' || newChildren === null) {
102 return null;
103 }
104
105 switch (newChildren.$$typeof) {
106 case REACT_ELEMENT_TYPE:
107 {
108 /* $FlowFixMe(>=0.31.0): This is an unsafe cast. Consider adding a type
109 * annotation to the `newChildren` param of this
110 * function.
111 */
112 var element = newChildren;
113 if (existingChild && element.type === existingChild.type && element.key === existingChild.key) {
114 // Get the clone of the existing fiber.
115 var clone = shouldClone ? cloneFiber(existingChild, priority) : existingChild;
116 if (!shouldClone) {
117 // TODO: This might be lowering the priority of nested unfinished work.
118 clone.pendingWorkPriority = priority;
119 }
120 clone.pendingProps = element.props;
121 clone.sibling = null;
122 clone['return'] = returnFiber;
123 return clone;
124 }
125 var child = createFiberFromElement(element, priority);
126 child['return'] = returnFiber;
127 return child;
128 }
129
130 case REACT_COROUTINE_TYPE:
131 {
132 /* $FlowFixMe(>=0.31.0): No 'handler' property found in object type
133 */
134 var coroutine = newChildren;
135 var _child3 = createFiberFromCoroutine(coroutine, priority);
136 _child3['return'] = returnFiber;
137 return _child3;
138 }
139
140 case REACT_YIELD_TYPE:
141 {
142 // A yield results in a fragment fiber whose output is the continuation.
143 // TODO: When there is only a single child, we can optimize this to avoid
144 // the fragment.
145 /* $FlowFixMe(>=0.31.0): No 'continuation' property found in object
146 * type
147 */
148 var yieldNode = newChildren;
149 var reifiedYield = createReifiedYield(yieldNode);
150 var _child4 = createFiberFromYield(yieldNode, priority);
151 _child4.output = reifiedYield;
152 _child4['return'] = returnFiber;
153 return _child4;
154 }
155 }
156
157 if (isArray(newChildren)) {
158 var first = null;
159 var prev = null;
160 var existing = existingChild;
161 /* $FlowIssue(>=0.31.0) #12747709
162 *
163 * `Array.isArray` is matched syntactically for now until predicate
164 * support is complete.
165 */
166 for (var i = 0; i < newChildren.length; i++) {
167 var nextExisting = existing && existing.sibling;
168 if (prev == null) {
169 prev = createFirstChild(returnFiber, existing, newChildren[i], priority);
170 first = prev;
171 } else {
172 prev = createSubsequentChild(returnFiber, existing, prev, newChildren[i], priority);
173 }
174 if (prev && existing) {
175 // TODO: This is not correct because there could've been more
176 // than one sibling consumed but I don't want to return a tuple.
177 existing = nextExisting;
178 }
179 }
180 return first;
181 } else {
182 // TODO: Throw for unknown children.
183 return null;
184 }
185 }
186
187 // TODO: This API won't work because we'll need to transfer the side-effects of
188 // unmounting children to the returnFiber.
189 function reconcileChildFibers(returnFiber, currentFirstChild, newChildren, priority) {
190 return createFirstChild(returnFiber, currentFirstChild, newChildren, priority);
191 }
192
193 return reconcileChildFibers;
194}
195
196exports.reconcileChildFibers = ChildReconciler(true);
197
198exports.reconcileChildFibersInPlace = ChildReconciler(false);
199
200function cloneSiblings(current, workInProgress, returnFiber) {
201 workInProgress['return'] = returnFiber;
202 while (current.sibling) {
203 current = current.sibling;
204 workInProgress = workInProgress.sibling = cloneFiber(current, current.pendingWorkPriority);
205 workInProgress['return'] = returnFiber;
206 }
207 workInProgress.sibling = null;
208}
209
210exports.cloneChildFibers = function (current, workInProgress) {
211 if (!workInProgress.child) {
212 return;
213 }
214 if (current && workInProgress.child === current.child) {
215 // We use workInProgress.child since that lets Flow know that it can't be
216 // null since we validated that already. However, as the line above suggests
217 // they're actually the same thing.
218 var currentChild = workInProgress.child;
219 // TODO: This used to reset the pending priority. Not sure if that is needed.
220 // workInProgress.pendingWorkPriority = current.pendingWorkPriority;
221 // TODO: The below priority used to be set to NoWork which would've
222 // dropped work. This is currently unobservable but will become
223 // observable when the first sibling has lower priority work remaining
224 // than the next sibling. At that point we should add tests that catches
225 // this.
226 var newChild = cloneFiber(currentChild, currentChild.pendingWorkPriority);
227 workInProgress.child = newChild;
228 cloneSiblings(currentChild, newChild, workInProgress);
229 }
230
231 // If there is no alternate, then we don't need to clone the children.
232 // If the children of the alternate fiber is a different set, then we don't
233 // need to clone. We need to reset the return fiber though since we'll
234 // traverse down into them.
235 var child = workInProgress.child;
236 while (child) {
237 child['return'] = workInProgress;
238 child = child.sibling;
239 }
240};
\No newline at end of file