Skip to content
Closed
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
50 changes: 34 additions & 16 deletions src/renderers/shared/fiber/ReactFiberUpdateQueue.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ type PartialState<State, Props> =

type Callback = () => void;

type CallbackNode = {
callback: Callback,
next: CallbackNode | null,
};

type Update = {
priorityLevel: PriorityLevel,
partialState: PartialState<any, any>,
Expand All @@ -59,12 +64,28 @@ export type UpdateQueue = {
first: Update | null,
last: Update | null,
hasForceUpdate: boolean,
callbackList: null | Array<Callback>,

firstCallback: CallbackNode | null,
lastCallback: CallbackNode | null,

// Dev only
isProcessing?: boolean,
};

function pushCallback(queue : UpdateQueue, callback : Callback) {
const node = {
callback,
next: null,
};
if (!queue.firstCallback) {
queue.firstCallback = node;
}
if (queue.lastCallback) {
queue.lastCallback.next = node;
}
queue.lastCallback = node;
}

function comparePriority(a : PriorityLevel, b : PriorityLevel) : number {
// When comparing update priorities, treat sync and Task work as equal.
// TODO: Could we avoid the need for this by always coercing sync priority
Expand Down Expand Up @@ -96,15 +117,17 @@ function ensureUpdateQueue(fiber : Fiber) : UpdateQueue {
first: null,
last: null,
hasForceUpdate: false,
callbackList: null,
firstCallback: null,
lastCallback: null,
isProcessing: false,
};
} else {
queue = {
first: null,
last: null,
hasForceUpdate: false,
callbackList: null,
firstCallback: null,
lastCallback: null,
};
}

Expand All @@ -127,7 +150,8 @@ function cloneUpdateQueue(current : Fiber, workInProgress : Fiber) : UpdateQueue

// These fields are invalid by the time we clone from current. Reset them.
altQueue.hasForceUpdate = false;
altQueue.callbackList = null;
altQueue.firstCallback = null;
altQueue.lastCallback = null;
altQueue.isProcessing = false;

workInProgress.updateQueue = altQueue;
Expand Down Expand Up @@ -415,7 +439,6 @@ function beginUpdateQueue(
// a new state object.
let state = prevState;
let dontMutatePrevState = true;
let callbackList = null;
let update = queue.first;
while (update && comparePriority(update.priorityLevel, priorityLevel) <= 0) {
// Remove each update from the queue right before it is processed. That way
Expand Down Expand Up @@ -447,16 +470,13 @@ function beginUpdateQueue(
// Second condition ignores top-level unmount callbacks if they are not the
// last update in the queue, since a subsequent update will cause a remount.
if (update.callback && !(update.isTopLevelUnmount && update.next)) {
callbackList = callbackList || [];
callbackList.push(update.callback);
pushCallback(queue, update.callback);
workInProgress.effectTag |= CallbackEffect;
}
update = update.next;
}

queue.callbackList = callbackList;

if (!queue.first && !callbackList && !queue.hasForceUpdate) {
if (!queue.first && !queue.firstCallback && !queue.hasForceUpdate) {
// The queue is empty and there are no callbacks. We can reset it.
workInProgress.updateQueue = null;
}
Expand All @@ -470,13 +490,11 @@ function beginUpdateQueue(
exports.beginUpdateQueue = beginUpdateQueue;

function commitCallbacks(finishedWork : Fiber, queue : UpdateQueue, context : mixed) {
const callbackList = queue.callbackList;
if (!callbackList) {
return;
}
for (let i = 0; i < callbackList.length; i++) {
const callback = callbackList[i];
let node = queue.firstCallback;
while (node) {
const callback = node.callback;
callback.call(context);
node = node.next;
}
}
exports.commitCallbacks = commitCallbacks;