Transfer everything from Element onto the Fiber
This has a few benefits: 1) This allows the element to always remain on the young generation. 2) The key can be accessed on the fiber which is easier to keep as the same class and is directly accessible in the child reconciliation of every object. 3) This conveniently means that we don't have to create a fake element for continuations which was really hacky. We can still do the quick bailout of rerendered things using the props object which is also unique.
Sebastian Markbage committed
May 26, 2016 at 23:16 UTC
aa14d89c7da229e1bf162414bff87fd020d7218b
5 files changed
+43
-40
src/renderers/shared/fiber/ReactFiber.js
+27
-14
@@ -35,7 +35,17 @@ export type Fiber = {
35
child: ?Fiber,
36
sibling: ?Fiber,
37
38
- // Input is the data coming into process this fiber. Arguments.
38
+ // Unique identifier of this child.
39
+ key: ?string,
40
+
41
+ // The function/class/module associated with this fiber.
42
+ type: any,
43
+
44
+ // The ref last used to attach this node.
45
+ // I'll avoid adding an owner field for prod and model that as functions.
46
+ ref: null | (handle : ?Object) => void,
47
+
48
+ // Input is the data coming into process this fiber. Arguments. Props.
49
input: any, // This type will be more specific once we overload the tag.
50
// Output is the return value of this fiber, or a linked list of return values
51
// if this returns multiple values. Such as a fragment.
@@ -52,7 +62,7 @@ export type Fiber = {
62
63
};
64
55
-var createFiber = function(tag : number) : Fiber {
65
+var createFiber = function(tag : number, key : null | string) : Fiber {
66
return {
67
68
tag: tag,
@@ -61,6 +71,10 @@ var createFiber = function(tag : number) : Fiber {
71
child: null,
72
sibling: null,
73
74
+ key: key,
75
+ type: null,
76
+ ref: null,
77
+
78
input: null,
79
output: null,
80
@@ -78,23 +92,21 @@ function shouldConstruct(Component) {
92
}
93
94
exports.createFiberFromElement = function(element : ReactElement) {
81
- const fiber = exports.createFiberFromElementType(element.type);
82
- if (typeof element.type === 'object') {
83
- // Hacky McHack
84
- element = ReactElement(fiber.input, null, element.ref, null, null, null, element.props);
85
- }
86
- fiber.input = element;
95
+ const fiber = exports.createFiberFromElementType(element.type, element.key);
96
+ fiber.input = element.props;
97
return fiber;
98
};
99
90
-exports.createFiberFromElementType = function(type : mixed) {
100
+exports.createFiberFromElementType = function(type : mixed, key : null | string) {
101
let fiber;
102
if (typeof type === 'function') {
103
fiber = shouldConstruct(type) ?
94
- createFiber(ClassComponent) :
95
- createFiber(IndeterminateComponent);
104
+ createFiber(ClassComponent, key) :
105
+ createFiber(IndeterminateComponent, key);
106
+ fiber.type = type;
107
} else if (typeof type === 'string') {
97
- fiber = createFiber(HostComponent);
108
+ fiber = createFiber(HostComponent, key);
109
+ fiber.type = type;
110
} else if (typeof type === 'object' && type !== null) {
111
// Currently assumed to be a continuation and therefore is a fiber already.
112
fiber = type;
@@ -105,12 +117,13 @@ exports.createFiberFromElementType = function(type : mixed) {
117
};
118
119
exports.createFiberFromCoroutine = function(coroutine : ReactCoroutine) {
108
- const fiber = createFiber(CoroutineComponent);
120
+ const fiber = createFiber(CoroutineComponent, coroutine.key);
121
+ fiber.type = coroutine.handler;
122
fiber.input = coroutine;
123
return fiber;
124
};
125
126
exports.createFiberFromYield = function(yieldNode : ReactYield) {
114
- const fiber = createFiber(YieldComponent);
127
+ const fiber = createFiber(YieldComponent, yieldNode.key);
128
return fiber;
129
};
src/renderers/shared/fiber/ReactFiberBeginWork.js
+7
-18
@@ -26,18 +26,9 @@ var {
26
YieldComponent,
27
} = ReactTypesOfWork;
28
29
-function getElement(unitOfWork) : ReactElement {
30
- var element = unitOfWork.input;
31
- if (!element) {
32
- throw new Error('Should be resolved by now');
33
- }
34
- return (element : ReactElement);
35
-}
36
-
29
function updateFunctionalComponent(unitOfWork) {
38
- var element = getElement(unitOfWork);
39
- var fn = element.type;
40
- var props = element.props;
30
+ var fn = unitOfWork.type;
31
+ var props = unitOfWork.input;
32
console.log('perform work on:', fn.name);
33
var nextChildren = fn(props);
34
@@ -49,10 +40,9 @@ function updateFunctionalComponent(unitOfWork) {
40
}
41
42
function updateHostComponent(unitOfWork) {
52
- var element = getElement(unitOfWork);
53
- console.log('host component', element.type, typeof element.props.children === 'string' ? element.props.children : '');
43
+ console.log('host component', unitOfWork.type, typeof unitOfWork.input.children === 'string' ? unitOfWork.input.children : '');
44
55
- var nextChildren = element.props.children;
45
+ var nextChildren = unitOfWork.input.children;
46
unitOfWork.child = ReactChildFiber.reconcileChildFibers(
47
unitOfWork,
48
unitOfWork.child,
@@ -61,9 +51,8 @@ function updateHostComponent(unitOfWork) {
51
}
52
53
function mountIndeterminateComponent(unitOfWork) {
64
- var element = getElement(unitOfWork);
65
- var fn = element.type;
66
- var props = element.props;
54
+ var fn = unitOfWork.type;
55
+ var props = unitOfWork.input;
56
var value = fn(props);
57
if (typeof value === 'object' && value && typeof value.render === 'function') {
58
console.log('performed work on class:', fn.name);
@@ -86,7 +75,7 @@ function updateCoroutineComponent(unitOfWork) {
75
if (!coroutine) {
76
throw new Error('Should be resolved by now');
77
}
89
- console.log('begin coroutine', coroutine.handler.name);
78
+ console.log('begin coroutine', unitOfWork.type.name);
79
unitOfWork.child = ReactChildFiber.reconcileChildFibers(
80
unitOfWork,
81
unitOfWork.child,
src/renderers/shared/fiber/ReactFiberCompleteWork.js
+3
-3
@@ -94,15 +94,15 @@ function handleCoroutine(unitOfWork : Fiber) {
94
exports.completeWork = function(unitOfWork : Fiber) : ?Fiber {
95
switch (unitOfWork.tag) {
96
case FunctionalComponent:
97
- console.log('/functional component', unitOfWork.input.type.name);
97
+ console.log('/functional component', unitOfWork.type.name);
98
transferOutput(unitOfWork.child, unitOfWork);
99
break;
100
case ClassComponent:
101
- console.log('/class component', unitOfWork.input.type.name);
101
+ console.log('/class component', unitOfWork.type.name);
102
transferOutput(unitOfWork.child, unitOfWork);
103
break;
104
case HostComponent:
105
- console.log('/host component', unitOfWork.input.type);
105
+ console.log('/host component', unitOfWork.type);
106
break;
107
case CoroutineComponent:
108
console.log('/coroutine component', unitOfWork.input.handler.name);
src/renderers/shared/fiber/ReactReifiedYield.js
+4
-3
@@ -20,9 +20,10 @@ var ReactFiber = require('ReactFiber');
20
export type ReifiedYield = { continuation: Fiber, props: Object };
21
22
exports.createReifiedYield = function(yieldNode : ReactYield) : ReifiedYield {
23
- var fiber = ReactFiber.createFiberFromElementType(yieldNode.continuation);
24
- // Hacky way to store the continuation
25
- fiber.input = yieldNode.continuation;
23
+ var fiber = ReactFiber.createFiberFromElementType(
24
+ yieldNode.continuation,
25
+ yieldNode.key
26
+ );
27
return {
28
continuation: fiber,
29
props: yieldNode.props,
src/renderers/shared/fiber/isomorphic/ReactCoroutine.js
+2
-2
@@ -29,7 +29,7 @@ type CoroutineHandler<T> = (props: T, yields: Array<ReifiedYield>) => ReactNodeL
29
30
export type ReactCoroutine = {
31
$$typeof: Symbol | number,
32
- key: ?string,
32
+ key: null | string,
33
children: any,
34
// This should be a more specific CoroutineHandler
35
handler: (props: any, yields: Array<ReifiedYield>) => ReactNodeList,
@@ -37,7 +37,7 @@ export type ReactCoroutine = {
37
};
38
export type ReactYield = {
39
$$typeof: Symbol | number,
40
- key: ?string,
40
+ key: null | string,
41
props: Object,
42
continuation: mixed
43
};