UNPKG

6.17 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 ReactTypeOfWork = require('./ReactTypeOfWork');
13var IndeterminateComponent = ReactTypeOfWork.IndeterminateComponent,
14 ClassComponent = ReactTypeOfWork.ClassComponent,
15 HostContainer = ReactTypeOfWork.HostContainer,
16 HostComponent = ReactTypeOfWork.HostComponent,
17 CoroutineComponent = ReactTypeOfWork.CoroutineComponent,
18 YieldComponent = ReactTypeOfWork.YieldComponent;
19
20var _require = require('./ReactPriorityLevel'),
21 NoWork = _require.NoWork;
22
23// An Instance is shared between all versions of a component. We can easily
24// break this out into a separate object to avoid copying so much to the
25// alternate versions of the tree. We put this on a single object for now to
26// minimize the number of objects created during the initial render.
27
28
29// A Fiber is work on a Component that needs to be done or was done. There can
30// be more than one per component.
31
32
33// This is a constructor of a POJO instead of a constructor function for a few
34// reasons:
35// 1) Nobody should add any instance methods on this. Instance methods can be
36// more difficult to predict when they get optimized and they are almost
37// never inlined properly in static compilers.
38// 2) Nobody should rely on `instanceof Fiber` for type testing. We should
39// always know when it is a fiber.
40// 3) We can easily go from a createFiber call to calling a constructor if that
41// is faster. The opposite is not true.
42// 4) We might want to experiment with using numeric keys since they are easier
43// to optimize in a non-JIT environment.
44// 5) It should be easy to port this to a C struct and keep a C implementation
45// compatible.
46var createFiber = function (tag, key) {
47 return {
48 // Instance
49
50 tag: tag,
51
52 key: key,
53
54 type: null,
55
56 stateNode: null,
57
58 // Fiber
59
60 'return': null,
61
62 child: null,
63 sibling: null,
64
65 ref: null,
66
67 pendingProps: null,
68 memoizedProps: null,
69 updateQueue: null,
70 memoizedState: null,
71 callbackList: null,
72 output: null,
73
74 nextEffect: null,
75 firstEffect: null,
76 lastEffect: null,
77
78 pendingWorkPriority: NoWork,
79 progressedPriority: NoWork,
80 progressedChild: null,
81
82 alternate: null
83 };
84};
85
86function shouldConstruct(Component) {
87 return !!(Component.prototype && Component.prototype.isReactComponent);
88}
89
90// This is used to create an alternate fiber to do work on.
91// TODO: Rename to createWorkInProgressFiber or something like that.
92exports.cloneFiber = function (fiber, priorityLevel) {
93 // We clone to get a work in progress. That means that this fiber is the
94 // current. To make it safe to reuse that fiber later on as work in progress
95 // we need to reset its work in progress flag now. We don't have an
96 // opportunity to do this earlier since we don't traverse the tree when
97 // the work in progress tree becomes the current tree.
98 // fiber.progressedPriority = NoWork;
99 // fiber.progressedChild = null;
100
101 // We use a double buffering pooling technique because we know that we'll only
102 // ever need at most two versions of a tree. We pool the "other" unused node
103 // that we're free to reuse. This is lazily created to avoid allocating extra
104 // objects for things that are never updated. It also allow us to reclaim the
105 // extra memory if needed.
106 var alt = fiber.alternate;
107 if (alt) {
108 // Whenever we clone, we do so to get a new work in progress.
109 // This ensures that we've reset these in the new tree.
110 alt.nextEffect = null;
111 alt.firstEffect = null;
112 alt.lastEffect = null;
113 } else {
114 // This should not have an alternate already
115 alt = createFiber(fiber.tag, fiber.key);
116 alt.type = fiber.type;
117
118 alt.progressedChild = fiber.progressedChild;
119 alt.progressedPriority = fiber.progressedPriority;
120
121 alt.alternate = fiber;
122 fiber.alternate = alt;
123 }
124
125 alt.stateNode = fiber.stateNode;
126 alt.child = fiber.child;
127 alt.sibling = fiber.sibling; // This should always be overridden. TODO: null
128 alt.ref = fiber.ref;
129 // pendingProps is here for symmetry but is unnecessary in practice for now.
130 // TODO: Pass in the new pendingProps as an argument maybe?
131 alt.pendingProps = fiber.pendingProps;
132 alt.updateQueue = fiber.updateQueue;
133 alt.callbackList = fiber.callbackList;
134 alt.pendingWorkPriority = priorityLevel;
135
136 alt.memoizedProps = fiber.memoizedProps;
137 alt.output = fiber.output;
138
139 return alt;
140};
141
142exports.createHostContainerFiber = function () {
143 var fiber = createFiber(HostContainer, null);
144 return fiber;
145};
146
147exports.createFiberFromElement = function (element, priorityLevel) {
148 // $FlowFixMe: ReactElement.key is currently defined as ?string but should be defined as null | string in Flow.
149 var fiber = createFiberFromElementType(element.type, element.key);
150 fiber.pendingProps = element.props;
151 fiber.pendingWorkPriority = priorityLevel;
152 return fiber;
153};
154
155function createFiberFromElementType(type, key) {
156 var fiber = void 0;
157 if (typeof type === 'function') {
158 fiber = shouldConstruct(type) ? createFiber(ClassComponent, key) : createFiber(IndeterminateComponent, key);
159 fiber.type = type;
160 } else if (typeof type === 'string') {
161 fiber = createFiber(HostComponent, key);
162 fiber.type = type;
163 } else if (typeof type === 'object' && type !== null) {
164 // Currently assumed to be a continuation and therefore is a fiber already.
165 fiber = type;
166 } else {
167 throw new Error('Unknown component type: ' + typeof type);
168 }
169 return fiber;
170}
171
172exports.createFiberFromElementType = createFiberFromElementType;
173
174exports.createFiberFromCoroutine = function (coroutine, priorityLevel) {
175 var fiber = createFiber(CoroutineComponent, coroutine.key);
176 fiber.type = coroutine.handler;
177 fiber.pendingProps = coroutine;
178 fiber.pendingWorkPriority = priorityLevel;
179 return fiber;
180};
181
182exports.createFiberFromYield = function (yieldNode, priorityLevel) {
183 var fiber = createFiber(YieldComponent, yieldNode.key);
184 fiber.pendingProps = {};
185 return fiber;
186};
\No newline at end of file