UNPKG

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