Skip to content

Commit

Permalink
refactor to use updateQueue
Browse files Browse the repository at this point in the history
  • Loading branch information
josephsavona committed Sep 8, 2022
1 parent 22f89ed commit bebca2f
Show file tree
Hide file tree
Showing 8 changed files with 89 additions and 120 deletions.
10 changes: 0 additions & 10 deletions packages/react-reconciler/src/ReactFiber.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
allowConcurrentByDefault,
enableTransitionTracing,
enableDebugTracing,
enableUseMemoCacheHook,
} from 'shared/ReactFeatureFlags';
import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
import {ConcurrentRoot} from './ReactRootTags';
Expand Down Expand Up @@ -145,9 +144,6 @@ function FiberNode(
this.updateQueue = null;
this.memoizedState = null;
this.dependencies = null;
if (enableUseMemoCacheHook) {
this.memoCache = null;
}

this.mode = mode;

Expand Down Expand Up @@ -314,9 +310,6 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
if (enableUseMemoCacheHook) {
workInProgress.memoCache = current.memoCache;
}

// Clone the dependencies object. This is mutated during the render phase, so
// it cannot be shared with the current fiber.
Expand Down Expand Up @@ -858,9 +851,6 @@ export function assignFiberPropertiesInDEV(
target.pendingProps = source.pendingProps;
target.memoizedProps = source.memoizedProps;
target.updateQueue = source.updateQueue;
if (enableUseMemoCacheHook) {
target.memoCache = source.memoCache;
}
target.memoizedState = source.memoizedState;
target.dependencies = source.dependencies;
target.mode = source.mode;
Expand Down
10 changes: 0 additions & 10 deletions packages/react-reconciler/src/ReactFiber.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ import {
allowConcurrentByDefault,
enableTransitionTracing,
enableDebugTracing,
enableUseMemoCacheHook,
} from 'shared/ReactFeatureFlags';
import {NoFlags, Placement, StaticMask} from './ReactFiberFlags';
import {ConcurrentRoot} from './ReactRootTags';
Expand Down Expand Up @@ -145,9 +144,6 @@ function FiberNode(
this.updateQueue = null;
this.memoizedState = null;
this.dependencies = null;
if (enableUseMemoCacheHook) {
this.memoCache = null;
}

this.mode = mode;

Expand Down Expand Up @@ -314,9 +310,6 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
workInProgress.memoizedProps = current.memoizedProps;
workInProgress.memoizedState = current.memoizedState;
workInProgress.updateQueue = current.updateQueue;
if (enableUseMemoCacheHook) {
workInProgress.memoCache = current.memoCache;
}

// Clone the dependencies object. This is mutated during the render phase, so
// it cannot be shared with the current fiber.
Expand Down Expand Up @@ -858,9 +851,6 @@ export function assignFiberPropertiesInDEV(
target.pendingProps = source.pendingProps;
target.memoizedProps = source.memoizedProps;
target.updateQueue = source.updateQueue;
if (enableUseMemoCacheHook) {
target.memoCache = source.memoCache;
}
target.memoizedState = source.memoizedState;
target.dependencies = source.dependencies;
target.mode = source.mode;
Expand Down
88 changes: 42 additions & 46 deletions packages/react-reconciler/src/ReactFiberHooks.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ import type {
Usable,
Thenable,
} from 'shared/ReactTypes';
import type {Fiber, Dispatcher, HookType} from './ReactInternalTypes';
import type {
Fiber,
Dispatcher,
HookType,
MemoCache,
} from './ReactInternalTypes';
import type {Lanes, Lane} from './ReactFiberLane.new';
import type {HookFlags} from './ReactHookEffectTags';
import type {FiberRoot} from './ReactInternalTypes';
Expand Down Expand Up @@ -173,6 +178,7 @@ type StoreConsistencyCheck<T> = {|
export type FunctionComponentUpdateQueue = {|
lastEffect: Effect | null,
stores: Array<StoreConsistencyCheck<any>> | null,
memoCache: MemoCache | null,
|};

type BasicStateAction<S> = (S => S) | S;
Expand Down Expand Up @@ -395,20 +401,6 @@ export function renderWithHooks<Props, SecondArg>(
current !== null && current.type !== workInProgress.type;
}

// Reset the memoCache index and create a backup copy in case of a setState during render
// or error, either of which can leave the cache in an inconsistent state
let previousMemoCache = null;
if (enableUseMemoCacheHook) {
previousMemoCache = workInProgress.memoCache;
if (previousMemoCache !== null) {
const memoCache = {
data: previousMemoCache.data.map(array => array.slice()),
index: 0,
};
workInProgress.memoCache = memoCache;
}
}

workInProgress.memoizedState = null;
workInProgress.updateQueue = null;
workInProgress.lanes = NoLanes;
Expand Down Expand Up @@ -480,17 +472,6 @@ export function renderWithHooks<Props, SecondArg>(

workInProgress.updateQueue = null;

if (enableUseMemoCacheHook) {
if (previousMemoCache !== null) {
// Setting state during render could leave the cache in an inconsistent state,
// reset to the previous state before re-rendering.
workInProgress.memoCache = {
data: previousMemoCache.data.map(array => array.slice()),
index: 0,
};
}
}

if (__DEV__) {
// Also validate hook order for cascading updates.
hookTypesUpdateIndexDev = -1;
Expand Down Expand Up @@ -604,7 +585,7 @@ export function bailoutHooks(
current.lanes = removeLanes(current.lanes, lanes);
}

export function resetHooksAfterThrow(erroredWork: Fiber | null): void {
export function resetHooksAfterThrow(): void {
// We can assume the previous dispatcher is always this one, since we set it
// at the beginning of the render phase and there's no re-entrance.
ReactCurrentDispatcher.current = ContextOnlyDispatcher;
Expand All @@ -629,18 +610,6 @@ export function resetHooksAfterThrow(erroredWork: Fiber | null): void {
didScheduleRenderPhaseUpdate = false;
}

if (enableUseMemoCacheHook) {
if (erroredWork != null) {
const memoCache = erroredWork.memoCache;
if (memoCache !== null) {
// The memo cache may be in an inconsistent state, reset to the version from
// the alternate if available, or clear the cache completely.
const alternate = erroredWork.alternate;
erroredWork.memoCache = alternate != null ? alternate.memoCache : null;
}
}
}

renderLanes = NoLanes;
currentlyRenderingFiber = (null: any);

Expand Down Expand Up @@ -747,6 +716,7 @@ function createFunctionComponentUpdateQueue(): FunctionComponentUpdateQueue {
return {
lastEffect: null,
stores: null,
memoCache: null,
};
}

Expand Down Expand Up @@ -818,22 +788,48 @@ function use<T>(usable: Usable<T>): T {
}

function useMemoCache(size: number): Array<any> {
let memoCache = currentlyRenderingFiber.memoCache;
let memoCache = null;
// Fast-path, load memo cache from wip fiber if already prepared
let updateQueue: FunctionComponentUpdateQueue | null = (currentlyRenderingFiber.updateQueue: any);
if (updateQueue !== null) {
memoCache = updateQueue.memoCache;
}
// Otherwise clone from the current fiber
// TODO: not sure how to access the current fiber here other than going through
// currentlyRenderingFiber.alternate
if (memoCache === null) {
const current: Fiber | null = currentlyRenderingFiber.alternate;
if (current !== null) {
const currentUpdateQueue: FunctionComponentUpdateQueue | null = (current.updateQueue: any);
if (currentUpdateQueue !== null) {
const currentMemoCache: MemoCache | null = currentUpdateQueue.memoCache;
if (currentMemoCache !== null) {
memoCache = {
data: currentMemoCache.data.map(array => array.slice()),
index: 0,
};
}
}
}
}
// Finally fall back to allocating a fresh instance
if (memoCache === null) {
memoCache = currentlyRenderingFiber.memoCache = {
memoCache = {
data: [],
index: 0,
};
}
if (updateQueue === null) {
updateQueue = createFunctionComponentUpdateQueue();
currentlyRenderingFiber.updateQueue = updateQueue;
}
updateQueue.memoCache = memoCache;

let data = memoCache.data[memoCache.index];
if (data === undefined) {
data = memoCache.data[memoCache.index] = new Array(size);
} else if (data.length !== size) {
if (__DEV__) {
console.warn(
'Expected each useMemoCache to receive a consistent size argument, found different sizes',
);
}
// TODO: consider warning or throwing here
}
memoCache.index++;
return data;
Expand Down
88 changes: 42 additions & 46 deletions packages/react-reconciler/src/ReactFiberHooks.old.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ import type {
Usable,
Thenable,
} from 'shared/ReactTypes';
import type {Fiber, Dispatcher, HookType} from './ReactInternalTypes';
import type {
Fiber,
Dispatcher,
HookType,
MemoCache,
} from './ReactInternalTypes';
import type {Lanes, Lane} from './ReactFiberLane.old';
import type {HookFlags} from './ReactHookEffectTags';
import type {FiberRoot} from './ReactInternalTypes';
Expand Down Expand Up @@ -173,6 +178,7 @@ type StoreConsistencyCheck<T> = {|
export type FunctionComponentUpdateQueue = {|
lastEffect: Effect | null,
stores: Array<StoreConsistencyCheck<any>> | null,
memoCache: MemoCache | null,
|};

type BasicStateAction<S> = (S => S) | S;
Expand Down Expand Up @@ -395,20 +401,6 @@ export function renderWithHooks<Props, SecondArg>(
current !== null && current.type !== workInProgress.type;
}

// Reset the memoCache index and create a backup copy in case of a setState during render
// or error, either of which can leave the cache in an inconsistent state
let previousMemoCache = null;
if (enableUseMemoCacheHook) {
previousMemoCache = workInProgress.memoCache;
if (previousMemoCache !== null) {
const memoCache = {
data: previousMemoCache.data.map(array => array.slice()),
index: 0,
};
workInProgress.memoCache = memoCache;
}
}

workInProgress.memoizedState = null;
workInProgress.updateQueue = null;
workInProgress.lanes = NoLanes;
Expand Down Expand Up @@ -480,17 +472,6 @@ export function renderWithHooks<Props, SecondArg>(

workInProgress.updateQueue = null;

if (enableUseMemoCacheHook) {
if (previousMemoCache !== null) {
// Setting state during render could leave the cache in an inconsistent state,
// reset to the previous state before re-rendering.
workInProgress.memoCache = {
data: previousMemoCache.data.map(array => array.slice()),
index: 0,
};
}
}

if (__DEV__) {
// Also validate hook order for cascading updates.
hookTypesUpdateIndexDev = -1;
Expand Down Expand Up @@ -604,7 +585,7 @@ export function bailoutHooks(
current.lanes = removeLanes(current.lanes, lanes);
}

export function resetHooksAfterThrow(erroredWork: Fiber | null): void {
export function resetHooksAfterThrow(): void {
// We can assume the previous dispatcher is always this one, since we set it
// at the beginning of the render phase and there's no re-entrance.
ReactCurrentDispatcher.current = ContextOnlyDispatcher;
Expand All @@ -629,18 +610,6 @@ export function resetHooksAfterThrow(erroredWork: Fiber | null): void {
didScheduleRenderPhaseUpdate = false;
}

if (enableUseMemoCacheHook) {
if (erroredWork != null) {
const memoCache = erroredWork.memoCache;
if (memoCache !== null) {
// The memo cache may be in an inconsistent state, reset to the version from
// the alternate if available, or clear the cache completely.
const alternate = erroredWork.alternate;
erroredWork.memoCache = alternate != null ? alternate.memoCache : null;
}
}
}

renderLanes = NoLanes;
currentlyRenderingFiber = (null: any);

Expand Down Expand Up @@ -747,6 +716,7 @@ function createFunctionComponentUpdateQueue(): FunctionComponentUpdateQueue {
return {
lastEffect: null,
stores: null,
memoCache: null,
};
}

Expand Down Expand Up @@ -818,22 +788,48 @@ function use<T>(usable: Usable<T>): T {
}

function useMemoCache(size: number): Array<any> {
let memoCache = currentlyRenderingFiber.memoCache;
let memoCache = null;
// Fast-path, load memo cache from wip fiber if already prepared
let updateQueue: FunctionComponentUpdateQueue | null = (currentlyRenderingFiber.updateQueue: any);
if (updateQueue !== null) {
memoCache = updateQueue.memoCache;
}
// Otherwise clone from the current fiber
// TODO: not sure how to access the current fiber here other than going through
// currentlyRenderingFiber.alternate
if (memoCache === null) {
const current: Fiber | null = currentlyRenderingFiber.alternate;
if (current !== null) {
const currentUpdateQueue: FunctionComponentUpdateQueue | null = (current.updateQueue: any);
if (currentUpdateQueue !== null) {
const currentMemoCache: MemoCache | null = currentUpdateQueue.memoCache;
if (currentMemoCache !== null) {
memoCache = {
data: currentMemoCache.data.map(array => array.slice()),
index: 0,
};
}
}
}
}
// Finally fall back to allocating a fresh instance
if (memoCache === null) {
memoCache = currentlyRenderingFiber.memoCache = {
memoCache = {
data: [],
index: 0,
};
}
if (updateQueue === null) {
updateQueue = createFunctionComponentUpdateQueue();
currentlyRenderingFiber.updateQueue = updateQueue;
}
updateQueue.memoCache = memoCache;

let data = memoCache.data[memoCache.index];
if (data === undefined) {
data = memoCache.data[memoCache.index] = new Array(size);
} else if (data.length !== size) {
if (__DEV__) {
console.warn(
'Expected each useMemoCache to receive a consistent size argument, found different sizes',
);
}
// TODO: consider warning or throwing here
}
memoCache.index++;
return data;
Expand Down
4 changes: 2 additions & 2 deletions packages/react-reconciler/src/ReactFiberWorkLoop.new.js
Original file line number Diff line number Diff line change
Expand Up @@ -1691,7 +1691,7 @@ function prepareFreshStack(root: FiberRoot, lanes: Lanes): Fiber {
function handleThrow(root, thrownValue): void {
// Reset module-level state that was set during the render phase.
resetContextDependencies();
resetHooksAfterThrow(workInProgress);
resetHooksAfterThrow();
resetCurrentDebugFiberInDEV();
// TODO: I found and added this missing line while investigating a
// separate issue. Write a regression test using string refs.
Expand Down Expand Up @@ -3307,7 +3307,7 @@ if (__DEV__ && replayFailedUnitOfWorkWithInvokeGuardedCallback) {
// Keep this code in sync with handleThrow; any changes here must have
// corresponding changes there.
resetContextDependencies();
resetHooksAfterThrow(unitOfWork);
resetHooksAfterThrow();
// Don't reset current debug fiber, since we're about to work on the
// same fiber again.

Expand Down
Loading

0 comments on commit bebca2f

Please sign in to comment.