@samitouri / QOS-React / commits / aa14d89c7d

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 };