Skip to content

Commit

Permalink
[WIP] Decouple update queue from Fiber type
Browse files Browse the repository at this point in the history
The update queue is in need of a refactor. Recent bugfixes (facebook#12528) have
exposed some flaws in how it's modeled. Upcoming features like Suspense
and [redacted] also rely on the update queue in ways that weren't
anticipated in the original design.

Major changes:

- Instead of boolean flags for `isReplace` and `isForceUpdate`, updates
have a `tag` field (like Fiber). This lowers the cost for adding new
types of updates.
- Render phase updates are special cased. Updates scheduled during
the render phase are dropped if the work-in-progress does not commit.
This is used for `getDerivedStateFrom{Props,Catch}`.
- `callbackList` has been replaced with a generic effect list. Aside
from callbacks, this is also used for `componentDidCatch`.

TODO:

- [x] Class components
- [ ] Host roots
- [ ] Fix Flow
  • Loading branch information
acdlite committed Apr 10, 2018
1 parent 76b4ba0 commit 6fdc713
Show file tree
Hide file tree
Showing 11 changed files with 1,072 additions and 460 deletions.
54 changes: 24 additions & 30 deletions packages/react-reconciler/src/ReactFiberBeginWork.js
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,12 @@ import {
ContextConsumer,
} from 'shared/ReactTypeOfWork';
import {
NoEffect,
PerformedWork,
Placement,
ContentReset,
Ref,
DidCapture,
} from 'shared/ReactTypeOfSideEffect';
import {ReactCurrentOwner} from 'shared/ReactGlobalSharedState';
import {
Expand All @@ -58,7 +60,12 @@ import {
reconcileChildFibers,
cloneChildFibers,
} from './ReactChildFiber';
import {processUpdateQueue} from './ReactFiberUpdateQueue';
import {processUpdateQueue as processLegacyUpdateQueue} from './ReactFiberUpdateQueue';
import {
createDeriveStateFromPropsUpdate,
enqueueRenderPhaseUpdate,
processUpdateQueue,
} from './ReactUpdateQueue';
import {NoWork, Never} from './ReactFiberExpirationTime';
import {AsyncMode, StrictMode} from './ReactTypeOfMode';
import MAX_SIGNED_31_BIT_INT from './maxSigned31BitInt';
Expand Down Expand Up @@ -260,7 +267,11 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
if (current === null) {
if (workInProgress.stateNode === null) {
// In the initial pass we might need to construct the instance.
constructClassInstance(workInProgress, workInProgress.pendingProps);
constructClassInstance(
workInProgress,
workInProgress.pendingProps,
renderExpirationTime,
);
mountClassInstance(workInProgress, renderExpirationTime);

shouldUpdate = true;
Expand All @@ -278,22 +289,11 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
renderExpirationTime,
);
}

// We processed the update queue inside updateClassInstance. It may have
// included some errors that were dispatched during the commit phase.
// TODO: Refactor class components so this is less awkward.
let didCaptureError = false;
const updateQueue = workInProgress.updateQueue;
if (updateQueue !== null && updateQueue.capturedValues !== null) {
shouldUpdate = true;
didCaptureError = true;
}
return finishClassComponent(
current,
workInProgress,
shouldUpdate,
hasContext,
didCaptureError,
renderExpirationTime,
);
}
Expand All @@ -303,12 +303,14 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
workInProgress: Fiber,
shouldUpdate: boolean,
hasContext: boolean,
didCaptureError: boolean,
renderExpirationTime: ExpirationTime,
) {
// Refs should update even if shouldComponentUpdate returns false
markRef(current, workInProgress);

const didCaptureError =
(workInProgress.effectTag & DidCapture) !== NoEffect;

if (!shouldUpdate && !didCaptureError) {
// Context providers should defer to sCU for rendering
if (hasContext) {
Expand Down Expand Up @@ -414,7 +416,7 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
let updateQueue = workInProgress.updateQueue;
if (updateQueue !== null) {
const prevState = workInProgress.memoizedState;
const state = processUpdateQueue(
const state = processLegacyUpdateQueue(
current,
workInProgress,
updateQueue,
Expand Down Expand Up @@ -607,20 +609,13 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
workInProgress.memoizedState =
value.state !== null && value.state !== undefined ? value.state : null;

if (typeof Component.getDerivedStateFromProps === 'function') {
const partialState = callGetDerivedStateFromProps(
workInProgress,
value,
props,
workInProgress.memoizedState,
);

if (partialState !== null && partialState !== undefined) {
workInProgress.memoizedState = Object.assign(
{},
workInProgress.memoizedState,
partialState,
);
const getDerivedStateFromProps = Component.getDerivedStateFromProps;
if (typeof getDerivedStateFromProps === 'function') {
const update = createDeriveStateFromPropsUpdate(renderExpirationTime);
enqueueRenderPhaseUpdate(workInProgress, update, renderExpirationTime);
const updateQueue = workInProgress.updateQueue;
if (updateQueue !== null) {
processUpdateQueue(workInProgress, updateQueue, renderExpirationTime);
}
}

Expand All @@ -635,7 +630,6 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
workInProgress,
true,
hasContext,
false,
renderExpirationTime,
);
} else {
Expand Down
Loading

0 comments on commit 6fdc713

Please sign in to comment.