Skip to content

Commit

Permalink
Regression test: startTransition in render phase
Browse files Browse the repository at this point in the history
useTransition uses the state hook as part of its implementation, so we
need to fork it in the re-render dispatcher, too.
  • Loading branch information
acdlite committed Dec 16, 2019
1 parent a37b65e commit 85b2209
Show file tree
Hide file tree
Showing 2 changed files with 37 additions and 3 deletions.
17 changes: 14 additions & 3 deletions packages/react-reconciler/src/ReactFiberHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -1243,6 +1243,17 @@ function updateTransition(
return [start, isPending];
}

function rerenderTransition(
config: SuspenseConfig | void | null,
): [(() => void) => void, boolean] {
const [isPending, setPending] = rerenderState(false);
const start = updateCallback(startTransition.bind(null, setPending, config), [
setPending,
config,
]);
return [start, isPending];
}

function dispatchAction<S, A>(
fiber: Fiber,
queue: UpdateQueue<S, A>,
Expand Down Expand Up @@ -1421,7 +1432,7 @@ const HooksDispatcherOnRerender: Dispatcher = {
useDebugValue: updateDebugValue,
useResponder: createResponderListener,
useDeferredValue: updateDeferredValue,
useTransition: updateTransition,
useTransition: rerenderTransition,
};

let HooksDispatcherOnMountInDEV: Dispatcher | null = null;
Expand Down Expand Up @@ -1920,7 +1931,7 @@ if (__DEV__) {
): [(() => void) => void, boolean] {
currentHookNameInDev = 'useTransition';
updateHookTypesDev();
return updateTransition(config);
return rerenderTransition(config);
},
};

Expand Down Expand Up @@ -2313,7 +2324,7 @@ if (__DEV__) {
currentHookNameInDev = 'useTransition';
warnInvalidHookAccess();
updateHookTypesDev();
return updateTransition(config);
return rerenderTransition(config);
},
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -645,6 +645,29 @@ describe('ReactHooksWithNoopRenderer', () => {
expect(Scheduler).toFlushAndYield(['B:0']);
expect(root).toMatchRenderedOutput(<span prop="B:0" />);
});

// TODO: This should probably warn
it('calling startTransition inside render phase', async () => {
let startTransition;
function App() {
let [counter, setCounter] = useState(0);
let [_startTransition] = useTransition();
startTransition = _startTransition;

if (counter === 0) {
startTransition(() => {
setCounter(c => c + 1);
});
}

return <Text text={counter} />;
}

const root = ReactNoop.createRoot();
root.render(<App />);
expect(Scheduler).toFlushAndYield([1]);
expect(root).toMatchRenderedOutput(<span prop={1} />);
});
});

describe('useReducer', () => {
Expand Down

0 comments on commit 85b2209

Please sign in to comment.