mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
Batch nested updates when in sync mode
Almost working...
This commit is contained in:
1 parent
78aef38bfa
commit
ecf468e556
4 files changed
+46
-23
No files matched your search
@@ -112,6 +112,8 @@ var DOMRenderer = ReactFiberReconciler({
|
||||
|
||||
scheduleDeferredCallback: window.requestIdleCallback,
|
||||
|
||||
useSyncScheduling: true,
|
||||
|
||||
});
|
||||
|
||||
var warned = false;
|
||||
|
||||
@@ -130,7 +130,7 @@ module.exports = function(scheduleUpdate : (fiber: Fiber, priorityLevel : ?Prior
|
||||
// process them now.
|
||||
const updateQueue = workInProgress.updateQueue;
|
||||
if (updateQueue) {
|
||||
instance.state = mergeUpdateQueue(updateQueue, state, props);
|
||||
instance.state = mergeUpdateQueue(updateQueue, instance, state, props);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -174,7 +174,7 @@ module.exports = function(scheduleUpdate : (fiber: Fiber, priorityLevel : ?Prior
|
||||
// process them now.
|
||||
const newUpdateQueue = workInProgress.updateQueue;
|
||||
if (newUpdateQueue) {
|
||||
newInstance.state = mergeUpdateQueue(newUpdateQueue, newState, newProps);
|
||||
newInstance.state = mergeUpdateQueue(newUpdateQueue, newInstance, newState, newProps);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
@@ -211,7 +211,7 @@ module.exports = function(scheduleUpdate : (fiber: Fiber, priorityLevel : ?Prior
|
||||
// TODO: Previous state can be null.
|
||||
let newState;
|
||||
if (updateQueue) {
|
||||
newState = mergeUpdateQueue(updateQueue, previousState, newProps);
|
||||
newState = mergeUpdateQueue(updateQueue, instance, previousState, newProps);
|
||||
} else {
|
||||
newState = previousState;
|
||||
}
|
||||
|
||||
@@ -71,6 +71,9 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
|
||||
SynchronousPriority :
|
||||
LowPriority;
|
||||
|
||||
// Whether updates should be batched. Only applies when using sync scheduling.
|
||||
let shouldBatchUpdates : boolean = false;
|
||||
|
||||
// The next work in progress fiber that we're currently working on.
|
||||
let nextUnitOfWork : ?Fiber = null;
|
||||
let nextPriorityLevel : PriorityLevel = NoWork;
|
||||
@@ -490,9 +493,10 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
|
||||
while (nextUnitOfWork &&
|
||||
nextPriorityLevel === SynchronousPriority) {
|
||||
nextUnitOfWork = performUnitOfWork(nextUnitOfWork, false);
|
||||
// If there's no nextUnitOfWork, we don't need to search for more
|
||||
// because it shouldn't be possible to schedule sync work without
|
||||
// immediately performing it
|
||||
|
||||
if (!nextUnitOfWork) {
|
||||
nextUnitOfWork = findNextUnitOfWork();
|
||||
}
|
||||
}
|
||||
if (nextUnitOfWork) {
|
||||
if (nextPriorityLevel > AnimationPriority) {
|
||||
@@ -504,7 +508,35 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
|
||||
}
|
||||
|
||||
function performSynchronousWork() {
|
||||
if (useSyncScheduling) {
|
||||
// Start batching updates
|
||||
shouldBatchUpdates = true;
|
||||
}
|
||||
performAndHandleErrors(performSynchronousWorkUnsafe);
|
||||
shouldBatchUpdates = false;
|
||||
}
|
||||
|
||||
function scheduleSynchronousWork(root : FiberRoot) {
|
||||
root.current.pendingWorkPriority = SynchronousPriority;
|
||||
|
||||
if (root.isScheduled) {
|
||||
// If we're already scheduled, we can bail out.
|
||||
return;
|
||||
}
|
||||
root.isScheduled = true;
|
||||
if (lastScheduledRoot) {
|
||||
// Schedule ourselves to the end.
|
||||
lastScheduledRoot.nextScheduledRoot = root;
|
||||
lastScheduledRoot = root;
|
||||
} else {
|
||||
// We're the only work scheduled.
|
||||
nextScheduledRoot = root;
|
||||
lastScheduledRoot = root;
|
||||
|
||||
if (!shouldBatchUpdates) {
|
||||
performSynchronousWork();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function performAndHandleErrors<A>(fn: (a: A) => void, a: A) {
|
||||
@@ -560,10 +592,9 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
|
||||
|
||||
// We will process an update caused by each error boundary synchronously.
|
||||
affectedBoundaries.forEach(boundary => {
|
||||
// FIXME: We only specify LowPriority here so that setState() calls from the error
|
||||
// boundaries are respected. Instead we should set default priority level or something
|
||||
// like this. Reconsider this piece when synchronous scheduling is in place.
|
||||
const priority = LowPriority;
|
||||
const priority = priorityContext !== null ?
|
||||
priorityContext :
|
||||
defaultPriorityContext;
|
||||
const root = scheduleErrorBoundaryWork(boundary, priority);
|
||||
// This should use findNextUnitOfWork() when synchronous scheduling is implemented.
|
||||
let fiber = cloneFiber(root.current, priority);
|
||||
@@ -604,8 +635,7 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
|
||||
}
|
||||
|
||||
if (priorityLevel === SynchronousPriority) {
|
||||
root.current.pendingWorkPriority = SynchronousPriority;
|
||||
performSynchronousWork();
|
||||
scheduleSynchronousWork(root);
|
||||
}
|
||||
|
||||
if (priorityLevel === NoWork) {
|
||||
@@ -626,15 +656,6 @@ module.exports = function<T, P, I, TI, C>(config : HostConfig<T, P, I, TI, C>) {
|
||||
defaultPriorityContext;
|
||||
}
|
||||
|
||||
// Don't bother bubbling the priority to the root if it is synchronous. Just
|
||||
// perform it now.
|
||||
if (priorityLevel === SynchronousPriority) {
|
||||
fiber.pendingWorkPriority = SynchronousPriority;
|
||||
nextUnitOfWork = fiber;
|
||||
performSynchronousWork();
|
||||
return;
|
||||
}
|
||||
|
||||
while (true) {
|
||||
if (fiber.pendingWorkPriority === NoWork ||
|
||||
fiber.pendingWorkPriority >= priorityLevel) {
|
||||
|
||||
@@ -73,14 +73,14 @@ exports.callCallbacks = function(queue : UpdateQueue, context : any) {
|
||||
}
|
||||
};
|
||||
|
||||
exports.mergeUpdateQueue = function(queue : UpdateQueue, prevState : any, props : any) : any {
|
||||
exports.mergeUpdateQueue = function(queue : UpdateQueue, instance : any, prevState : any, props : any) : any {
|
||||
let node : ?UpdateQueueNode = queue;
|
||||
let state = queue.isReplace ? null : Object.assign({}, prevState);
|
||||
while (node) {
|
||||
let partialState;
|
||||
if (typeof node.partialState === 'function') {
|
||||
const updateFn = node.partialState;
|
||||
partialState = updateFn(state, props);
|
||||
partialState = updateFn.call(instance, state, props);
|
||||
} else {
|
||||
partialState = node.partialState;
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user