Skip to content

Commit

Permalink
Child Fiber
Browse files Browse the repository at this point in the history
  • Loading branch information
sebmarkbage committed May 27, 2016
1 parent 2636155 commit 7c8a090
Show file tree
Hide file tree
Showing 8 changed files with 301 additions and 77 deletions.
17 changes: 10 additions & 7 deletions src/renderers/noop/__tests__/ReactNoop-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ describe('ReactComponent', function() {
ReactNoop = require('ReactNoop');
});

it('should render a simple component', function() {
/*it('should render a simple component', function() {
function Bar() {
return <div>Hello World</div>;
Expand All @@ -33,24 +33,27 @@ describe('ReactComponent', function() {
ReactNoop.render(<Foo />);
ReactNoop.flush();
});
});*/

it('should render a simple component, in steps if needed', function() {

function Bar() {
return <div>Hello World</div>;
return <span><div>Hello World</div></span>;
}

function Foo() {
return <Bar isBar={true} />;
return [
<Bar isBar={true} />,
<Bar isBar={true} />,
];
}

ReactNoop.render(<Foo />);
// console.log('Nothing done');
console.log('Nothing done');
ReactNoop.flushLowPri(7);
// console.log('Yield');
console.log('Yield');
ReactNoop.flushLowPri(50);
// console.log('Done');
console.log('Done');
});


Expand Down
86 changes: 86 additions & 0 deletions src/renderers/shared/fiber/ReactChildFiber.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactChildFiber
* @flow
*/

'use strict';

import type { Fiber } from 'ReactFiber';

var ReactElement = require('ReactElement');

var ReactFiber = require('ReactFiber');

type ReactNode = ReactElement | ReactFragment | ReactText;

type ReactFragment = Iterable<ReactNode | ReactEmpty>;

type ReactNodeList = ReactNode | ReactEmpty;

type ReactText = string | number;

type ReactEmpty = null | void | boolean;

function createSubsequentChild(parent : Fiber, previousSibling : Fiber, newChildren) : Fiber {
if (typeof newChildren !== 'object' || newChildren === null) {
return previousSibling;
}

if (ReactElement.isValidElement(newChildren)) {
var element = (newChildren : ReactElement);
var child = ReactFiber.createFiberFromElement(element);
previousSibling.sibling = child;
child.parent = parent;
return child;
}

if (Array.isArray(newChildren)) {
let prev : Fiber = previousSibling;
for (var i = 0; i < newChildren.length; i++) {
prev = createSubsequentChild(parent, prev, newChildren[i]);
}
return prev;
} else {
return previousSibling;
}
}

function createFirstChild(parent, newChildren) {
if (typeof newChildren !== 'object' || newChildren === null) {
parent.child = null;
return null;
}

if (ReactElement.isValidElement(newChildren)) {
var element = (newChildren : ReactElement);
var child = ReactFiber.createFiberFromElement(element);
parent.child = child;
child.parent = parent;
return child;
}

if (Array.isArray(newChildren)) {
var prev : ?Fiber = null;
for (var i = 0; i < newChildren.length; i++) {
if (prev == null) {
prev = createFirstChild(parent, newChildren[i]);
} else {
prev = createSubsequentChild(parent, prev, newChildren[i]);
}
}
} else {
parent.child = null;
return null;
}
}

exports.reconcileChildFibers = function(parent : Fiber, newChildren : ReactNodeList) : void {
createFirstChild(parent, newChildren);
};
35 changes: 28 additions & 7 deletions src/renderers/shared/fiber/ReactFiber.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,13 @@

'use strict';

var ReactTypesOfWork = require('ReactTypesOfWork');
var {
IndeterminateComponent,
ClassComponent,
HostComponent,
} = ReactTypesOfWork;

type StateNode = {};
type EffectHandler = () => void;
type EffectTag = number;
Expand All @@ -27,16 +34,13 @@ export type Fiber = {
input: ?Object,
output: ?Object,

handler: EffectHandler,
handlerTag: EffectTag,

hasPendingChanges: bool,

stateNode: StateNode,

};

module.exports = function(tag : number) : Fiber {
var createFiber = function(tag : number, handlerTag : number) : Fiber {
return {

tag: tag,
Expand All @@ -48,12 +52,29 @@ module.exports = function(tag : number) : Fiber {
input: null,
output: null,

handler: function() {},
handlerTag: 0,

hasPendingChanges: true,

stateNode: {},

};
};

function shouldConstruct(Component) {
return !!(Component.prototype && Component.prototype.isReactComponent);
}

exports.createFiberFromElement = function(element : ReactElement) {
let fiber;
if (typeof element.type === 'function') {
fiber = shouldConstruct(element.type) ?
createFiber(ClassComponent, 0) :
createFiber(IndeterminateComponent, 0);
} else if (typeof element.type === 'string') {
fiber = createFiber(HostComponent, 1);
} else {
throw new Error('Unknown component type: ' + typeof element.type);
}

fiber.input = element;
return fiber;
};
97 changes: 97 additions & 0 deletions src/renderers/shared/fiber/ReactFiberBeginWork.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactFiberBeginWork
* @flow
*/

'use strict';

import type { Fiber } from 'ReactFiber';

var ReactChildFiber = require('ReactChildFiber');
var ReactTypesOfWork = require('ReactTypesOfWork');
var {
IndeterminateComponent,
FunctionalComponent,
ClassComponent,
HostComponent,
} = ReactTypesOfWork;

function getElement(unitOfWork) : ReactElement {
var element = unitOfWork.input;
if (!element) {
throw new Error('Should be resolved by now');
}
return (element : ReactElement);
}

function updateFunctionalComponent(unitOfWork) {
var element = getElement(unitOfWork);
var fn = element.type;
var props = element.props;
console.log('perform work on:', fn.name);
var nextChildren = fn(props);

ReactChildFiber.reconcileChildFibers(
unitOfWork,
nextChildren
);
}

function updateHostComponent(unitOfWork) {
var element = getElement(unitOfWork);
console.log('host component', element.type);

var nextChildren = element.props.children;
ReactChildFiber.reconcileChildFibers(
unitOfWork,
nextChildren
);
}

function mountIndeterminateComponent(unitOfWork) {
var element = getElement(unitOfWork);
var fn = element.type;
var props = element.props;
var value = fn(props);
if (typeof value === 'object' && value && typeof value.render === 'function') {
console.log('performed work on class:', fn.name);
// Proceed under the assumption that this is a class instance
unitOfWork.tag = ClassComponent;
} else {
console.log('performed work on fn:', fn.name);
// Proceed under the assumption that this is a functional component
unitOfWork.tag = FunctionalComponent;
}
ReactChildFiber.reconcileChildFibers(
unitOfWork,
value
);
}

exports.beginWork = function(unitOfWork : Fiber) : ?Fiber {
switch (unitOfWork.tag) {
case IndeterminateComponent:
mountIndeterminateComponent(unitOfWork);
break;
case FunctionalComponent:
updateFunctionalComponent(unitOfWork);
break;
case ClassComponent:
// $FlowFixMe
console.log('class component', unitOfWork.input.type.name);
break;
case HostComponent:
updateHostComponent(unitOfWork);
break;
default:
throw new Error('Unknown unit of work tag');
}
return unitOfWork.child;
};
46 changes: 46 additions & 0 deletions src/renderers/shared/fiber/ReactFiberCompleteWork.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Copyright 2013-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactFiberCompleteWork
* @flow
*/

'use strict';

import type { Fiber } from 'ReactFiber';

var ReactChildFiber = require('ReactChildFiber');
var ReactTypesOfWork = require('ReactTypesOfWork');
var {
IndeterminateComponent,
FunctionalComponent,
ClassComponent,
HostComponent,
} = ReactTypesOfWork;

exports.completeWork = function(unitOfWork : Fiber) : ?Fiber {
switch (unitOfWork.tag) {
case FunctionalComponent:
// $FlowFixMe
console.log('/functional component', unitOfWork.input.type.name);
break;
case ClassComponent:
// $FlowFixMe
console.log('/class component', unitOfWork.input.type.name);
break;
case HostComponent:
// $FlowFixMe
console.log('/host component', unitOfWork.input.type);
break;
case IndeterminateComponent:
throw new Error('An indeterminate component should have become determinate before completing.');
default:
throw new Error('Unknown unit of work tag');
}
return null;
};
45 changes: 0 additions & 45 deletions src/renderers/shared/fiber/ReactFiberFunctionalComponent.js

This file was deleted.

Loading

0 comments on commit 7c8a090

Please sign in to comment.