Skip to content

Commit 7166ce6

Browse files
committed
[WIP] This will all make sense, soon
1 parent 8e5f12c commit 7166ce6

15 files changed

+1398
-33
lines changed

packages/react-reconciler/src/ReactFiber.js

+5
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import {
2929
Mode,
3030
ContextProvider,
3131
ContextConsumer,
32+
TimeoutComponent,
3233
} from 'shared/ReactTypeOfWork';
3334
import getComponentName from 'shared/getComponentName';
3435

@@ -42,6 +43,7 @@ import {
4243
REACT_PROVIDER_TYPE,
4344
REACT_CONTEXT_TYPE,
4445
REACT_ASYNC_MODE_TYPE,
46+
REACT_TIMEOUT_TYPE,
4547
} from 'shared/ReactSymbols';
4648

4749
let hasBadMapPolyfill;
@@ -347,6 +349,9 @@ export function createFiberFromElement(
347349
case REACT_RETURN_TYPE:
348350
fiberTag = ReturnComponent;
349351
break;
352+
case REACT_TIMEOUT_TYPE:
353+
fiberTag = TimeoutComponent;
354+
break;
350355
default: {
351356
if (typeof type === 'object' && type !== null) {
352357
switch (type.$$typeof) {

packages/react-reconciler/src/ReactFiberBeginWork.js

+71-2
Original file line numberDiff line numberDiff line change
@@ -30,11 +30,14 @@ import {
3030
Mode,
3131
ContextProvider,
3232
ContextConsumer,
33+
TimeoutComponent,
3334
} from 'shared/ReactTypeOfWork';
3435
import {
36+
NoEffect,
3537
PerformedWork,
3638
Placement,
3739
ContentReset,
40+
DidCapture,
3841
Ref,
3942
} from 'shared/ReactTypeOfSideEffect';
4043
import {ReactCurrentOwner} from 'shared/ReactGlobalSharedState';
@@ -83,8 +86,16 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
8386
config: HostConfig<T, P, I, TI, HI, PI, C, CC, CX, PL>,
8487
hostContext: HostContext<C, CX>,
8588
hydrationContext: HydrationContext<C, CX>,
86-
scheduleWork: (fiber: Fiber, expirationTime: ExpirationTime) => void,
87-
computeExpirationForFiber: (fiber: Fiber) => ExpirationTime,
89+
scheduleWork: (
90+
fiber: Fiber,
91+
startTime: ExpirationTime,
92+
expirationTime: ExpirationTime,
93+
) => void,
94+
computeExpirationForFiber: (
95+
startTime: ExpirationTime,
96+
fiber: Fiber,
97+
) => ExpirationTime,
98+
recalculateCurrentTime: () => ExpirationTime,
8899
) {
89100
const {shouldSetTextContent, shouldDeprioritizeSubtree} = config;
90101

@@ -108,6 +119,7 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
108119
computeExpirationForFiber,
109120
memoizeProps,
110121
memoizeState,
122+
recalculateCurrentTime,
111123
);
112124

113125
// TODO: Remove this and use reconcileChildrenAtExpirationTime directly.
@@ -716,6 +728,57 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
716728
return workInProgress.stateNode;
717729
}
718730

731+
function updateTimeoutComponent(
732+
current,
733+
workInProgress,
734+
renderExpirationTime,
735+
) {
736+
const nextProps = workInProgress.pendingProps;
737+
const prevProps = workInProgress.memoizedProps;
738+
739+
let nextState = workInProgress.memoizedState;
740+
if (nextState === null) {
741+
nextState = workInProgress.memoizedState = false;
742+
}
743+
const prevState = current === null ? nextState : current.memoizedState;
744+
745+
const updateQueue = workInProgress.updateQueue;
746+
if (updateQueue !== null) {
747+
nextState = workInProgress.memoizedState = processUpdateQueue(
748+
current,
749+
workInProgress,
750+
updateQueue,
751+
null,
752+
null,
753+
renderExpirationTime,
754+
);
755+
}
756+
757+
if (hasLegacyContextChanged()) {
758+
// Normally we can bail out on props equality but if context has changed
759+
// we don't do the bailout and we have to reuse existing props instead.
760+
} else if (
761+
// Don't bail out if this is a restart
762+
(workInProgress.effectTag & DidCapture) === NoEffect &&
763+
prevProps === nextProps &&
764+
prevState === nextState
765+
) {
766+
return bailoutOnAlreadyFinishedWork(current, workInProgress);
767+
}
768+
769+
if ((workInProgress.effectTag & DidCapture) !== NoEffect) {
770+
nextState = workInProgress.memoizedState = true;
771+
}
772+
773+
const isExpired = nextState;
774+
const render = nextProps.children;
775+
const nextChildren = render(isExpired);
776+
workInProgress.memoizedProps = nextProps;
777+
workInProgress.memoizedState = nextState;
778+
reconcileChildren(current, workInProgress, nextChildren);
779+
return workInProgress.child;
780+
}
781+
719782
function updatePortalComponent(
720783
current,
721784
workInProgress,
@@ -1092,6 +1155,12 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
10921155
// A return component is just a placeholder, we can just run through the
10931156
// next one immediately.
10941157
return null;
1158+
case TimeoutComponent:
1159+
return updateTimeoutComponent(
1160+
current,
1161+
workInProgress,
1162+
renderExpirationTime,
1163+
);
10951164
case HostPortal:
10961165
return updatePortalComponent(
10971166
current,

packages/react-reconciler/src/ReactFiberClassComponent.js

+19-8
Original file line numberDiff line numberDiff line change
@@ -110,10 +110,18 @@ function callGetDerivedStateFromCatch(ctor: any, capturedValues: Array<mixed>) {
110110
}
111111

112112
export default function(
113-
scheduleWork: (fiber: Fiber, expirationTime: ExpirationTime) => void,
114-
computeExpirationForFiber: (fiber: Fiber) => ExpirationTime,
113+
scheduleWork: (
114+
fiber: Fiber,
115+
startTime: ExpirationTime,
116+
expirationTime: ExpirationTime,
117+
) => void,
118+
computeExpirationForFiber: (
119+
startTime: ExpirationTime,
120+
fiber: Fiber,
121+
) => ExpirationTime,
115122
memoizeProps: (workInProgress: Fiber, props: any) => void,
116123
memoizeState: (workInProgress: Fiber, state: any) => void,
124+
recalculateCurrentTime: () => ExpirationTime,
117125
) {
118126
// Class component state updater
119127
const updater = {
@@ -124,7 +132,8 @@ export default function(
124132
if (__DEV__) {
125133
warnOnInvalidCallback(callback, 'setState');
126134
}
127-
const expirationTime = computeExpirationForFiber(fiber);
135+
const currentTime = recalculateCurrentTime();
136+
const expirationTime = computeExpirationForFiber(currentTime, fiber);
128137
const update = {
129138
expirationTime,
130139
partialState,
@@ -135,15 +144,16 @@ export default function(
135144
next: null,
136145
};
137146
insertUpdateIntoFiber(fiber, update);
138-
scheduleWork(fiber, expirationTime);
147+
scheduleWork(fiber, currentTime, expirationTime);
139148
},
140149
enqueueReplaceState(instance, state, callback) {
141150
const fiber = ReactInstanceMap.get(instance);
142151
callback = callback === undefined ? null : callback;
143152
if (__DEV__) {
144153
warnOnInvalidCallback(callback, 'replaceState');
145154
}
146-
const expirationTime = computeExpirationForFiber(fiber);
155+
const currentTime = recalculateCurrentTime();
156+
const expirationTime = computeExpirationForFiber(currentTime, fiber);
147157
const update = {
148158
expirationTime,
149159
partialState: state,
@@ -154,15 +164,16 @@ export default function(
154164
next: null,
155165
};
156166
insertUpdateIntoFiber(fiber, update);
157-
scheduleWork(fiber, expirationTime);
167+
scheduleWork(fiber, currentTime, expirationTime);
158168
},
159169
enqueueForceUpdate(instance, callback) {
160170
const fiber = ReactInstanceMap.get(instance);
161171
callback = callback === undefined ? null : callback;
162172
if (__DEV__) {
163173
warnOnInvalidCallback(callback, 'forceUpdate');
164174
}
165-
const expirationTime = computeExpirationForFiber(fiber);
175+
const currentTime = recalculateCurrentTime();
176+
const expirationTime = computeExpirationForFiber(currentTime, fiber);
166177
const update = {
167178
expirationTime,
168179
partialState: null,
@@ -173,7 +184,7 @@ export default function(
173184
next: null,
174185
};
175186
insertUpdateIntoFiber(fiber, update);
176-
scheduleWork(fiber, expirationTime);
187+
scheduleWork(fiber, currentTime, expirationTime);
177188
},
178189
};
179190

packages/react-reconciler/src/ReactFiberCommitWork.js

+33
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import {
2525
HostText,
2626
HostPortal,
2727
CallComponent,
28+
TimeoutComponent,
2829
} from 'shared/ReactTypeOfWork';
2930
import ReactErrorUtils from 'shared/ReactErrorUtils';
3031
import {Placement, Update, ContentReset} from 'shared/ReactTypeOfSideEffect';
@@ -33,6 +34,7 @@ import invariant from 'fbjs/lib/invariant';
3334
import {commitCallbacks} from './ReactFiberUpdateQueue';
3435
import {onCommitUnmount} from './ReactFiberDevToolsHook';
3536
import {startPhaseTimer, stopPhaseTimer} from './ReactDebugFiberPerf';
37+
import {insertUpdateIntoFiber} from './ReactFiberUpdateQueue';
3638
import {logCapturedError} from './ReactFiberErrorLogger';
3739
import getComponentName from 'shared/getComponentName';
3840
import {getStackAddendumByWorkInProgressFiber} from 'shared/ReactFiberComponentTreeHook';
@@ -152,6 +154,22 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
152154
}
153155
}
154156

157+
function scheduleExpirationBoundaryRecovery(fiber) {
158+
const currentTime = recalculateCurrentTime();
159+
const expirationTime = computeExpirationForFiber(currentTime, fiber);
160+
const update = {
161+
expirationTime,
162+
partialState: false,
163+
callback: null,
164+
isReplace: true,
165+
isForced: false,
166+
capturedValue: null,
167+
next: null,
168+
};
169+
insertUpdateIntoFiber(fiber, update);
170+
scheduleWork(fiber, currentTime, expirationTime);
171+
}
172+
155173
function commitLifeCycles(
156174
finishedRoot: FiberRoot,
157175
current: Fiber | null,
@@ -226,6 +244,18 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
226244
// We have no life-cycles associated with portals.
227245
return;
228246
}
247+
case TimeoutComponent: {
248+
const updateQueue = finishedWork.updateQueue;
249+
if (updateQueue !== null) {
250+
const promises = updateQueue.capturedValues;
251+
if (promises !== null) {
252+
Promise.race(promises).then(() =>
253+
scheduleExpirationBoundaryRecovery(finishedWork),
254+
);
255+
}
256+
}
257+
return;
258+
}
229259
default: {
230260
invariant(
231261
false,
@@ -784,6 +814,9 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
784814
case HostRoot: {
785815
return;
786816
}
817+
case TimeoutComponent: {
818+
return;
819+
}
787820
default: {
788821
invariant(
789822
false,

packages/react-reconciler/src/ReactFiberCompleteWork.js

+6
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import {
3434
ContextConsumer,
3535
Fragment,
3636
Mode,
37+
TimeoutComponent,
3738
} from 'shared/ReactTypeOfWork';
3839
import {
3940
Placement,
@@ -605,6 +606,11 @@ export default function<T, P, I, TI, HI, PI, C, CC, CX, PL>(
605606
case ReturnComponent:
606607
// Does nothing.
607608
return null;
609+
case TimeoutComponent:
610+
if (workInProgress.effectTag & DidCapture) {
611+
workInProgress.effectTag |= Update;
612+
}
613+
return null;
608614
case Fragment:
609615
return null;
610616
case Mode:

0 commit comments

Comments
 (0)