Renamed fiber.parent -> fiber.return
This is not just the parent Instance but also the return Fiber for some piece of work. This clarifies and buys into this definition. Basically, in the current model you will always pass into a fiber from the parent that you're going to return to. Even if you get aborted and reused this will be updated to the correct return fiber before you get back here. I don't have any guarantees in place to enforce this right now. I don't really know how to, but seems safe. :) I confirmed that the use of keyword properties work for old engines because we have the transform enabled in our build system.
Sebastian Markbage committed
Jun 24, 2016 at 15:11 UTC
4a8651412ddb3ee745ae578e23966b422259fd94
6 files changed
+59
-61
src/renderers/shared/fiber/ReactChildFiber.js
+16
-16
@@ -29,7 +29,7 @@ var {
29
var ReactFiber = require('ReactFiber');
30
var ReactReifiedYield = require('ReactReifiedYield');
31
32
-function createSubsequentChild(parent : Fiber, existingChild : ?Fiber, previousSibling : Fiber, newChildren, priority : PriorityLevel) : Fiber {
32
+function createSubsequentChild(returnFiber : Fiber, existingChild : ?Fiber, previousSibling : Fiber, newChildren, priority : PriorityLevel) : Fiber {
33
if (typeof newChildren !== 'object' || newChildren === null) {
34
return previousSibling;
35
}
@@ -46,13 +46,13 @@ function createSubsequentChild(parent : Fiber, existingChild : ?Fiber, previousS
46
clone.pendingProps = element.props;
47
clone.child = existingChild.child;
48
clone.sibling = null;
49
- clone.parent = parent;
49
+ clone.return = returnFiber;
50
previousSibling.sibling = clone;
51
return clone;
52
}
53
const child = ReactFiber.createFiberFromElement(element, priority);
54
previousSibling.sibling = child;
55
- child.parent = parent;
55
+ child.return = returnFiber;
56
return child;
57
}
58
@@ -60,7 +60,7 @@ function createSubsequentChild(parent : Fiber, existingChild : ?Fiber, previousS
60
const coroutine = (newChildren : ReactCoroutine);
61
const child = ReactFiber.createFiberFromCoroutine(coroutine, priority);
62
previousSibling.sibling = child;
63
- child.parent = parent;
63
+ child.return = returnFiber;
64
return child;
65
}
66
@@ -70,7 +70,7 @@ function createSubsequentChild(parent : Fiber, existingChild : ?Fiber, previousS
70
const child = ReactFiber.createFiberFromYield(yieldNode, priority);
71
child.output = reifiedYield;
72
previousSibling.sibling = child;
73
- child.parent = parent;
73
+ child.return = returnFiber;
74
return child;
75
}
76
}
@@ -79,7 +79,7 @@ function createSubsequentChild(parent : Fiber, existingChild : ?Fiber, previousS
79
let prev : Fiber = previousSibling;
80
let existing : ?Fiber = existingChild;
81
for (var i = 0; i < newChildren.length; i++) {
82
- prev = createSubsequentChild(parent, existing, prev, newChildren[i], priority);
82
+ prev = createSubsequentChild(returnFiber, existing, prev, newChildren[i], priority);
83
if (prev && existing) {
84
// TODO: This is not correct because there could've been more
85
// than one sibling consumed but I don't want to return a tuple.
@@ -93,7 +93,7 @@ function createSubsequentChild(parent : Fiber, existingChild : ?Fiber, previousS
93
}
94
}
95
96
-function createFirstChild(parent, existingChild, newChildren, priority) {
96
+function createFirstChild(returnFiber, existingChild, newChildren, priority) {
97
if (typeof newChildren !== 'object' || newChildren === null) {
98
return null;
99
}
@@ -109,18 +109,18 @@ function createFirstChild(parent, existingChild, newChildren, priority) {
109
clone.pendingProps = element.props;
110
clone.child = existingChild.child;
111
clone.sibling = null;
112
- clone.parent = parent;
112
+ clone.return = returnFiber;
113
return clone;
114
}
115
const child = ReactFiber.createFiberFromElement(element, priority);
116
- child.parent = parent;
116
+ child.return = returnFiber;
117
return child;
118
}
119
120
case REACT_COROUTINE_TYPE: {
121
const coroutine = (newChildren : ReactCoroutine);
122
const child = ReactFiber.createFiberFromCoroutine(coroutine, priority);
123
- child.parent = parent;
123
+ child.return = returnFiber;
124
return child;
125
}
126
@@ -132,7 +132,7 @@ function createFirstChild(parent, existingChild, newChildren, priority) {
132
const reifiedYield = ReactReifiedYield.createReifiedYield(yieldNode);
133
const child = ReactFiber.createFiberFromYield(yieldNode, priority);
134
child.output = reifiedYield;
135
- child.parent = parent;
135
+ child.return = returnFiber;
136
return child;
137
}
138
}
@@ -143,10 +143,10 @@ function createFirstChild(parent, existingChild, newChildren, priority) {
143
var existing : ?Fiber = existingChild;
144
for (var i = 0; i < newChildren.length; i++) {
145
if (prev == null) {
146
- prev = createFirstChild(parent, existing, newChildren[i], priority);
146
+ prev = createFirstChild(returnFiber, existing, newChildren[i], priority);
147
first = prev;
148
} else {
149
- prev = createSubsequentChild(parent, existing, prev, newChildren[i], priority);
149
+ prev = createSubsequentChild(returnFiber, existing, prev, newChildren[i], priority);
150
}
151
if (prev && existing) {
152
// TODO: This is not correct because there could've been more
@@ -162,7 +162,7 @@ function createFirstChild(parent, existingChild, newChildren, priority) {
162
}
163
164
// TODO: This API won't work because we'll need to transfer the side-effects of
165
-// unmounting children to the parent.
166
-exports.reconcileChildFibers = function(parent : Fiber, currentFirstChild : ?Fiber, newChildren : ReactNodeList, priority : PriorityLevel) : ?Fiber {
167
- return createFirstChild(parent, currentFirstChild, newChildren, priority);
165
+// unmounting children to the returnFiber.
166
+exports.reconcileChildFibers = function(returnFiber : Fiber, currentFirstChild : ?Fiber, newChildren : ReactNodeList, priority : PriorityLevel) : ?Fiber {
167
+ return createFirstChild(returnFiber, currentFirstChild, newChildren, priority);
168
};
src/renderers/shared/fiber/ReactFiber.js
+18
-13
@@ -41,11 +41,6 @@ type Instance = {
41
// Tag identifying the type of fiber.
42
tag: TypeOfWork,
43
44
- // The parent Fiber used to create this one. The type is constrained to the
45
- // Instance part of the Fiber since it is not safe to traverse the tree from
46
- // the instance.
47
- parent: ?Instance, // Consider a regenerated temporary parent stack instead.
48
-
44
// Unique identifier of this child.
45
key: null | string,
46
@@ -55,12 +50,22 @@ type Instance = {
50
// The local state associated with this fiber.
51
stateNode: ?Object,
52
53
+ // Conceptual aliases
54
+ // parent : Instance -> return The parent happens to be the same as the
55
+ // return fiber since we've merged the fiber and instance.
56
+
57
};
58
59
// A Fiber is work on a Component that needs to be done or was done. There can
60
// be more than one per component.
61
export type Fiber = Instance & {
62
63
+ // The Fiber to return to after finishing processing this one.
64
+ // This is effectively the parent, but there can be multiple parents (two)
65
+ // so this is only the parent of the thing we're currently processing.
66
+ // It is conceptually the same as the return address of a stack frame.
67
+ return: ?Fiber,
68
+
69
// Singly Linked List Tree Structure.
70
child: ?Fiber,
71
sibling: ?Fiber,
@@ -71,8 +76,8 @@ export type Fiber = Instance & {
76
77
// Input is the data coming into process this fiber. Arguments. Props.
78
pendingProps: any, // This type will be more specific once we overload the tag.
74
- // TODO: I think that there is a way to merge input and memoizedProps somehow.
75
- memoizedProps: any, // The input used to create the output.
79
+ // TODO: I think that there is a way to merge pendingProps and memoizedProps.
80
+ memoizedProps: any, // The props used to create the output.
81
// Output is the return value of this fiber, or a linked list of return values
82
// if this returns multiple values. Such as a fragment.
83
output: any, // This type will be more specific once we overload the tag.
@@ -93,8 +98,8 @@ export type Fiber = Instance & {
98
hasWorkInProgress: bool,
99
100
// Conceptual aliases
96
- // parent : Instance -> returnFiber The parent happens to be the same as the return fiber.
97
- // workInProgress : Fiber -> alternate The alternate used for reuse happens to be the same as work in progress.
101
+ // workInProgress : Fiber -> alternate The alternate used for reuse happens
102
+ // to be the same as work in progress.
103
104
};
105
@@ -105,8 +110,6 @@ var createFiber = function(tag : TypeOfWork, key : null | string) : Fiber {
110
111
tag: tag,
112
108
- parent: null,
109
-
113
key: key,
114
115
type: null,
@@ -115,6 +118,8 @@ var createFiber = function(tag : TypeOfWork, key : null | string) : Fiber {
118
119
// Fiber
120
121
+ return: null,
122
+
123
child: null,
124
sibling: null,
125
@@ -126,10 +131,10 @@ var createFiber = function(tag : TypeOfWork, key : null | string) : Fiber {
131
132
pendingWorkPriority: NoWork,
133
129
- alternate: null,
130
-
134
hasWorkInProgress: false,
135
136
+ alternate: null,
137
+
138
};
139
};
140
src/renderers/shared/fiber/ReactFiberBeginWork.js
+7
-7
@@ -115,22 +115,22 @@ function updateCoroutineComponent(current, workInProgress) {
115
workInProgress.pendingWorkPriority = NoWork;
116
}
117
118
-function reuseChildren(newParent : Fiber, firstChild : Fiber) {
118
+function reuseChildren(returnFiber : Fiber, firstChild : Fiber) {
119
// TODO: None of this should be necessary if structured better.
120
- // The parent pointer only needs to be updated when we walk into this child
120
+ // The returnFiber pointer only needs to be updated when we walk into this child
121
// which we don't do right now. If the pending work priority indicated only
122
// if a child has work rather than if the node has work, then we would know
123
// by a single lookup on workInProgress rather than having to go through
124
// each child.
125
let child = firstChild;
126
do {
127
- // Update the parent of the child to the newest fiber.
128
- child.parent = newParent;
127
+ // Update the returnFiber of the child to the newest fiber.
128
+ child.return = returnFiber;
129
// Retain the priority if there's any work left to do in the children.
130
if (child.pendingWorkPriority !== NoWork &&
131
- (newParent.pendingWorkPriority === NoWork ||
132
- newParent.pendingWorkPriority > child.pendingWorkPriority)) {
133
- newParent.pendingWorkPriority = child.pendingWorkPriority;
131
+ (returnFiber.pendingWorkPriority === NoWork ||
132
+ returnFiber.pendingWorkPriority > child.pendingWorkPriority)) {
133
+ returnFiber.pendingWorkPriority = child.pendingWorkPriority;
134
}
135
} while (child = child.sibling);
136
}
src/renderers/shared/fiber/ReactFiberCompleteWork.js
+4
-4
@@ -30,12 +30,12 @@ var {
30
YieldComponent,
31
} = ReactTypeOfWork;
32
33
-function transferOutput(child : ?Fiber, parent : Fiber) {
33
+function transferOutput(child : ?Fiber, returnFiber : Fiber) {
34
// If we have a single result, we just pass that through as the output to
35
// avoid unnecessary traversal. When we have multiple output, we just pass
36
// the linked list of fibers that has the individual output values.
37
- parent.output = (child && !child.sibling) ? child.output : child;
38
- parent.memoizedProps = parent.pendingProps;
37
+ returnFiber.output = (child && !child.sibling) ? child.output : child;
38
+ returnFiber.memoizedProps = returnFiber.pendingProps;
39
}
40
41
function recursivelyFillYields(yields, output : ?Fiber | ?ReifiedYield) {
@@ -83,7 +83,7 @@ function moveCoroutineToHandlerPhase(current : ?Fiber, workInProgress : Fiber) {
83
var nextChildren = fn(props, yields);
84
85
var currentFirstChild = current ? current.stateNode : null;
86
- // Inherit the priority of the parent.
86
+ // Inherit the priority of the returnFiber.
87
const priority = workInProgress.pendingWorkPriority;
88
workInProgress.stateNode = ReactChildFiber.reconcileChildFibers(
89
workInProgress,
src/renderers/shared/fiber/ReactFiberPendingWork.js
+5
-7
@@ -21,14 +21,14 @@ var {
21
NoWork,
22
} = require('ReactPriorityLevel');
23
24
-function cloneSiblings(current : Fiber, workInProgress : Fiber, parent : Fiber) {
24
+function cloneSiblings(current : Fiber, workInProgress : Fiber, returnFiber : Fiber) {
25
while (current.sibling) {
26
current = current.sibling;
27
workInProgress = workInProgress.sibling = ReactFiber.cloneFiber(
28
current,
29
current.pendingWorkPriority
30
);
31
- workInProgress.parent = parent;
31
+ workInProgress.return = returnFiber;
32
}
33
workInProgress.sibling = null;
34
}
@@ -63,7 +63,7 @@ exports.findNextUnitOfWorkAtPriority = function(currentRoot : Fiber, priorityLev
63
}
64
workInProgress.pendingWorkPriority = current.pendingWorkPriority;
65
workInProgress.child = ReactFiber.cloneFiber(currentChild, NoWork);
66
- workInProgress.child.parent = workInProgress;
66
+ workInProgress.child.return = workInProgress;
67
cloneSiblings(currentChild, workInProgress.child, workInProgress);
68
current = current.child;
69
continue;
@@ -79,9 +79,7 @@ exports.findNextUnitOfWorkAtPriority = function(currentRoot : Fiber, priorityLev
79
return null;
80
}
81
while (!current.sibling) {
82
- // TODO: Stop using parent here. See below.
83
- // $FlowFixMe: This downcast is not safe. It is intentionally an error.
84
- current = current.parent;
82
+ current = current.return;
83
if (!current) {
84
return null;
85
}
@@ -95,4 +93,4 @@ exports.findNextUnitOfWorkAtPriority = function(currentRoot : Fiber, priorityLev
93
current = current.sibling;
94
}
95
return null;
98
-}
96
+};
src/renderers/shared/fiber/ReactFiberScheduler.js
+9
-14
@@ -94,29 +94,24 @@ module.exports = function<T, P, I>(config : HostConfig<T, P, I>) {
94
workInProgress.hasWorkInProgress = false;
95
}
96
97
- // TODO: Stop using the parent for this purpose. I think this will break
98
- // down in edge cases because when nodes are reused during bailouts, we
99
- // don't know which of two parents was used. Instead we should maintain
100
- // a temporary manual stack.
101
- // $FlowFixMe: This downcast is not safe. It is intentionally an error.
102
- const parent = workInProgress.parent;
97
+ const returnFiber = workInProgress.return;
98
99
// Ensure that remaining work priority bubbles up.
105
- if (parent && workInProgress.pendingWorkPriority !== NoWork &&
106
- (parent.pendingWorkPriority === NoWork ||
107
- parent.pendingWorkPriority > workInProgress.pendingWorkPriority)) {
108
- parent.pendingWorkPriority = workInProgress.pendingWorkPriority;
100
+ if (returnFiber && workInProgress.pendingWorkPriority !== NoWork &&
101
+ (returnFiber.pendingWorkPriority === NoWork ||
102
+ returnFiber.pendingWorkPriority > workInProgress.pendingWorkPriority)) {
103
+ returnFiber.pendingWorkPriority = workInProgress.pendingWorkPriority;
104
}
105
106
if (next) {
107
// If completing this work spawned new work, do that next.
108
return next;
109
} else if (workInProgress.sibling) {
115
- // If there is more work to do in this parent, do that next.
110
+ // If there is more work to do in this returnFiber, do that next.
111
return workInProgress.sibling;
117
- } else if (parent) {
118
- // If there's no more work in this parent. Complete the parent.
119
- workInProgress = parent;
112
+ } else if (returnFiber) {
113
+ // If there's no more work in this returnFiber. Complete the returnFiber.
114
+ workInProgress = returnFiber;
115
} else {
116
// If we're at the root, there's no more work to do. We can flush it.
117
const root : FiberRoot = (workInProgress.stateNode : any);