25
26
import type { ReactCoroutine, ReactYield } from 'ReactCoroutine';
27
28
-export type Fiber = {
28
+// An Instance is shared between all versions of a component. We can easily
29
+// break this out into a separate object to avoid copying so much to the
30
+// alternate versions of the tree. We put this on a single object for now to
31
+// minimize the number of objects created during the initial render.
32
+type Instance = {
33
34
// Tag identifying the type of fiber.
35
tag: number,
36
33
- // Singly Linked List Tree Structure.
34
- parent: ?Fiber, // Consider a regenerated temporary parent stack instead.
35
- child: ?Fiber,
36
- sibling: ?Fiber,
37
+ // The parent Fiber used to create this one. The type is constrained to the
38
+ // Instance part of the Fiber since it is not safe to traverse the tree from
39
+ // the instance.
40
+ parent: ?Instance, // Consider a regenerated temporary parent stack instead.
41
42
// Unique identifier of this child.
39
- key: ?string,
43
+ key: null | string,
44
45
// The function/class/module associated with this fiber.
46
type: any,
47
48
+ // The local state associated with this fiber.
49
+ stateNode: ?Object,
50
+
51
+};
52
+
53
+// A Fiber is work on a Component that needs to be done or was done. There can
54
+// be more than one per component.
55
+export type Fiber = Instance & {
56
+
57
+ // Singly Linked List Tree Structure.
58
+ child: ?Fiber,
59
+ sibling: ?Fiber,
60
+
61
// The ref last used to attach this node.
62
// I'll avoid adding an owner field for prod and model that as functions.
63
ref: null | (handle : ?Object) => void,
64
65
// Input is the data coming into process this fiber. Arguments. Props.
66
input: any, // This type will be more specific once we overload the tag.
67
+ // TODO: I think that there is a way to merge input and memoizedInput somehow.
68
+ memoizedInput: any, // The input used to create the output.
69
// Output is the return value of this fiber, or a linked list of return values
70
// if this returns multiple values. Such as a fragment.
71
output: any, // This type will be more specific once we overload the tag.
73
// This will be used to quickly determine if a subtree has no pending changes.
74
hasPendingChanges: bool,
75
57
- // The local state associated with this fiber.
58
- stateNode: ?Object,
76
+ // This is a pooled version of a Fiber. Every fiber that gets updated will
77
+ // eventually have a pair. There are cases when we can clean up pairs to save
78
+ // memory if we need to.
79
+ alternate: ?Fiber,
80
81
};
82
83
var createFiber = function(tag : number, key : null | string) : Fiber {
84
return {
85
86
+ // Instance
87
+
88
tag: tag,
89
90
parent: null,
68
- child: null,
69
- sibling: null,
91
92
key: key,
93
+
94
type: null,
95
+
96
+ stateNode: null,
97
+
98
+ // Fiber
99
+
100
+ child: null,
101
+ sibling: null,
102
+
103
ref: null,
104
105
input: null,
106
+ memoizedInput: null,
107
output: null,
108
109
hasPendingChanges: true,
110
80
- stateNode: null,
111
+ alternate: null,
112
113
};
114
};
117
return !!(Component.prototype && Component.prototype.isReactComponent);
118
}
119
120
+// This is used to create an alternate fiber to do work on.
121
+exports.cloneFiber = function(fiber : Fiber) : Fiber {
122
+ // We use a double buffering pooling technique because we know that we'll only
123
+ // ever need at most two versions of a tree. We pool the "other" unused node
124
+ // that we're free to reuse. This is lazily created to avoid allocating extra
125
+ // objects for things that are never updated. It also allow us to reclaim the
126
+ // extra memory if needed.
127
+ if (fiber.alternate) {
128
+ return fiber.alternate;
129
+ }
130
+ // This should not have an alternate already
131
+ var alt = createFiber(fiber.tag, fiber.key);
132
+
133
+ if (fiber.parent) {
134
+ // TODO: This assumes the parent's alternate is already created.
135
+ // Stop using the alternates of parents once we have a parent stack.
136
+ // $FlowFixMe: This downcast is not safe. It is intentionally an error.
137
+ alt.parent = fiber.parent.alternate;
138
+ }
139
+
140
+ alt.type = fiber.type;
141
+ alt.stateNode = fiber.stateNode;
142
+ alt.alternate = fiber;
143
+ fiber.alternate = alt;
144
+ return alt;
145
+};
146
+
147
exports.createFiberFromElement = function(element : ReactElement) {
148
const fiber = exports.createFiberFromElementType(element.type, element.key);
149
fiber.input = element.props;