Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/renderers/shared/fiber/ReactFiber.js
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,7 @@ exports.cloneFiber = function(fiber : Fiber, priorityLevel : PriorityLevel) : Fi
alt.pendingWorkPriority = priorityLevel;

alt.memoizedProps = fiber.memoizedProps;
alt.memoizedState = fiber.memoizedState;
alt.output = fiber.output;

return alt;
Expand Down
90 changes: 7 additions & 83 deletions src/renderers/shared/fiber/ReactFiberBeginWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,15 @@

import type { ReactCoroutine } from 'ReactCoroutine';
import type { Fiber } from 'ReactFiber';
import type { FiberRoot } from 'ReactFiberRoot';
import type { HostConfig } from 'ReactFiberReconciler';
import type { Scheduler } from 'ReactFiberScheduler';
import type { PriorityLevel } from 'ReactPriorityLevel';
import type { UpdateQueue } from 'ReactFiberUpdateQueue';

var {
mountChildFibersInPlace,
reconcileChildFibers,
reconcileChildFibersInPlace,
cloneChildFibers,
} = require('ReactChildFiber');
var { LowPriority } = require('ReactPriorityLevel');
var ReactTypeOfWork = require('ReactTypeOfWork');
var {
IndeterminateComponent,
Expand All @@ -45,17 +41,18 @@ var {
OffscreenPriority,
} = require('ReactPriorityLevel');
var {
createUpdateQueue,
addToQueue,
addCallbackToQueue,
mergeUpdateQueue,
} = require('ReactFiberUpdateQueue');
var {
Placement,
} = require('ReactTypeOfSideEffect');
var ReactInstanceMap = require('ReactInstanceMap');
var ReactFiberClassComponent = require('ReactFiberClassComponent');

module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>, getScheduler : () => Scheduler) {
module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>, scheduleUpdate : (fiber: Fiber, priorityLevel : PriorityLevel) => void) {

const {
mount,
} = ReactFiberClassComponent(scheduleUpdate);

function markChildAsProgressed(current, workInProgress, priorityLevel) {
// We now have clones. Let's store them as the currently progressed work.
Expand Down Expand Up @@ -158,72 +155,6 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>, g
return workInProgress.child;
}

function scheduleUpdate(fiber: Fiber, updateQueue: UpdateQueue, priorityLevel : PriorityLevel): void {
const { scheduleDeferredWork } = getScheduler();
fiber.updateQueue = updateQueue;
// Schedule update on the alternate as well, since we don't know which tree
// is current.
if (fiber.alternate) {
fiber.alternate.updateQueue = updateQueue;
}
while (true) {
if (fiber.pendingWorkPriority === NoWork ||
fiber.pendingWorkPriority >= priorityLevel) {
fiber.pendingWorkPriority = priorityLevel;
}
if (fiber.alternate) {
if (fiber.alternate.pendingWorkPriority === NoWork ||
fiber.alternate.pendingWorkPriority >= priorityLevel) {
fiber.alternate.pendingWorkPriority = priorityLevel;
}
}
// Duck type root
if (fiber.stateNode && fiber.stateNode.containerInfo) {
const root : FiberRoot = (fiber.stateNode : any);
scheduleDeferredWork(root, priorityLevel);
return;
}
if (!fiber.return) {
throw new Error('No root!');
}
fiber = fiber.return;
}
}

// Class component state updater
const updater = {
enqueueSetState(instance, partialState) {
const fiber = ReactInstanceMap.get(instance);
const updateQueue = fiber.updateQueue ?
addToQueue(fiber.updateQueue, partialState) :
createUpdateQueue(partialState);
scheduleUpdate(fiber, updateQueue, LowPriority);
},
enqueueReplaceState(instance, state) {
const fiber = ReactInstanceMap.get(instance);
const updateQueue = createUpdateQueue(state);
updateQueue.isReplace = true;
scheduleUpdate(fiber, updateQueue, LowPriority);
},
enqueueForceUpdate(instance) {
const fiber = ReactInstanceMap.get(instance);
const updateQueue = fiber.updateQueue || createUpdateQueue(null);
updateQueue.isForced = true;
scheduleUpdate(fiber, updateQueue, LowPriority);
},
enqueueCallback(instance, callback) {
const fiber = ReactInstanceMap.get(instance);
let updateQueue = fiber.updateQueue ?
fiber.updateQueue :
createUpdateQueue(null);
addCallbackToQueue(updateQueue, callback);
fiber.updateQueue = updateQueue;
if (fiber.alternate) {
fiber.alternate.updateQueue = updateQueue;
}
},
};

function updateClassComponent(current : ?Fiber, workInProgress : Fiber) {
// A class component update is the result of either new props or new state.
// Account for the possibly of missing pending props by falling back to the
Expand All @@ -243,15 +174,8 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>, g
if (!instance) {
var ctor = workInProgress.type;
workInProgress.stateNode = instance = new ctor(props);
mount(workInProgress, instance);
state = instance.state || null;
// The initial state must be added to the update queue in case
// setState is called before the initial render.
if (state !== null) {
workInProgress.updateQueue = createUpdateQueue(state);
}
// The instance needs access to the fiber so that it can schedule updates
ReactInstanceMap.set(instance, workInProgress);
instance.updater = updater;
} else if (typeof instance.shouldComponentUpdate === 'function' &&
!(updateQueue && updateQueue.isForced)) {
if (workInProgress.memoizedProps !== null) {
Expand Down
89 changes: 89 additions & 0 deletions src/renderers/shared/fiber/ReactFiberClassComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* 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 ReactFiberClassComponent
* @flow
*/

'use strict';

import type { Fiber } from 'ReactFiber';
import type { PriorityLevel } from 'ReactPriorityLevel';
import type { UpdateQueue } from 'ReactFiberUpdateQueue';

var { LowPriority } = require('ReactPriorityLevel');
var {
createUpdateQueue,
addToQueue,
addCallbackToQueue,
} = require('ReactFiberUpdateQueue');
var ReactInstanceMap = require('ReactInstanceMap');

module.exports = function(scheduleUpdate : (fiber: Fiber, priorityLevel : PriorityLevel) => void) {

function scheduleUpdateQueue(fiber: Fiber, updateQueue: UpdateQueue, priorityLevel : PriorityLevel) {
fiber.updateQueue = updateQueue;
// Schedule update on the alternate as well, since we don't know which tree
// is current.
if (fiber.alternate) {
fiber.alternate.updateQueue = updateQueue;
}
scheduleUpdate(fiber, priorityLevel);
}

// Class component state updater
const updater = {
enqueueSetState(instance, partialState) {
const fiber = ReactInstanceMap.get(instance);
const updateQueue = fiber.updateQueue ?
addToQueue(fiber.updateQueue, partialState) :
createUpdateQueue(partialState);
scheduleUpdateQueue(fiber, updateQueue, LowPriority);
},
enqueueReplaceState(instance, state) {
const fiber = ReactInstanceMap.get(instance);
const updateQueue = createUpdateQueue(state);
updateQueue.isReplace = true;
scheduleUpdateQueue(fiber, updateQueue, LowPriority);
},
enqueueForceUpdate(instance) {
const fiber = ReactInstanceMap.get(instance);
const updateQueue = fiber.updateQueue || createUpdateQueue(null);
updateQueue.isForced = true;
scheduleUpdateQueue(fiber, updateQueue, LowPriority);
},
enqueueCallback(instance, callback) {
const fiber = ReactInstanceMap.get(instance);
let updateQueue = fiber.updateQueue ?
fiber.updateQueue :
createUpdateQueue(null);
addCallbackToQueue(updateQueue, callback);
fiber.updateQueue = updateQueue;
if (fiber.alternate) {
fiber.alternate.updateQueue = updateQueue;
}
},
};

function mount(workInProgress : Fiber, instance : any) {
const state = instance.state || null;
// The initial state must be added to the update queue in case
// setState is called before the initial render.
if (state !== null) {
workInProgress.updateQueue = createUpdateQueue(state);
}
// The instance needs access to the fiber so that it can schedule updates
ReactInstanceMap.set(instance, workInProgress);
instance.updater = updater;
}

return {
mount,
};

};
4 changes: 1 addition & 3 deletions src/renderers/shared/fiber/ReactFiberCommitWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -289,9 +289,7 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
} else {
if (typeof instance.componentDidUpdate === 'function') {
const prevProps = current.memoizedProps;
// TODO: This is the new state. We don't currently have the previous
// state anymore.
const prevState = instance.state || null;
const prevState = current.memoizedState;
instance.componentDidUpdate(prevProps, prevState);
}
}
Expand Down
42 changes: 31 additions & 11 deletions src/renderers/shared/fiber/ReactFiberScheduler.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,17 @@ var {
Deletion,
} = require('ReactTypeOfSideEffect');

var timeHeuristicForUnitOfWork = 1;
var {
HostContainer,
} = require('ReactTypeOfWork');

export type Scheduler = {
scheduleDeferredWork: (root : FiberRoot, priority : PriorityLevel) => void
};
var timeHeuristicForUnitOfWork = 1;

module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
// Use a closure to circumvent the circular dependency between the scheduler
// and ReactFiberBeginWork. Don't know if there's a better way to do this.
let scheduler;
function getScheduler(): Scheduler {
return scheduler;
}

const { beginWork } = ReactFiberBeginWork(config, getScheduler);
const { beginWork } = ReactFiberBeginWork(config, scheduleUpdate);
const { completeWork } = ReactFiberCompleteWork(config);
const { commitInsertion, commitDeletion, commitWork, commitLifeCycles } =
ReactFiberCommitWork(config);
Expand Down Expand Up @@ -395,6 +391,31 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
scheduleAnimationWork(root, defaultPriority);
}

function scheduleUpdate(fiber: Fiber, priorityLevel : PriorityLevel): void {
while (true) {
if (fiber.pendingWorkPriority === NoWork ||
fiber.pendingWorkPriority >= priorityLevel) {
fiber.pendingWorkPriority = priorityLevel;
}
if (fiber.alternate) {
if (fiber.alternate.pendingWorkPriority === NoWork ||
fiber.alternate.pendingWorkPriority >= priorityLevel) {
fiber.alternate.pendingWorkPriority = priorityLevel;
}
}
if (!fiber.return) {
if (fiber.tag === HostContainer) {
const root : FiberRoot = (fiber.stateNode : any);
scheduleDeferredWork(root, priorityLevel);
return;
} else {
throw new Error('Invalid root');
}
}
fiber = fiber.return;
}
}

function performWithPriority(priorityLevel : PriorityLevel, fn : Function) {
const previousDefaultPriority = defaultPriority;
defaultPriority = priorityLevel;
Expand All @@ -405,10 +426,9 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
}
}

scheduler = {
return {
scheduleWork: scheduleWork,
scheduleDeferredWork: scheduleDeferredWork,
performWithPriority: performWithPriority,
};
return scheduler;
};
8 changes: 5 additions & 3 deletions src/renderers/shared/fiber/ReactFiberUpdateQueue.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ exports.createUpdateQueue = function(partialState : mixed) : UpdateQueue {
return queue;
};

exports.addToQueue = function(queue : UpdateQueue, partialState : mixed) : UpdateQueue {
function addToQueue(queue : UpdateQueue, partialState : mixed) : UpdateQueue {
const node = {
partialState,
callback: null,
Expand All @@ -49,12 +49,14 @@ exports.addToQueue = function(queue : UpdateQueue, partialState : mixed) : Updat
queue.tail.next = node;
queue.tail = node;
return queue;
};
}

exports.addToQueue = addToQueue;

exports.addCallbackToQueue = function(queue : UpdateQueue, callback: Function) : UpdateQueue {
if (queue.tail.callback) {
// If the tail already as a callback, add an empty node to queue
exports.addToQueue(queue, null);
addToQueue(queue, null);
}
queue.tail.callback = callback;
return queue;
Expand Down