Skip to content

Commit cb1ff43

Browse files
authored
Phased dispatcher (#14701)
* Move DEV-only function right above where it's used I don't like looking at this top-level function #petty * Use different dispatchers for functions & classes Classes support readContext, but not any of the other dispatcher methods. Function support all methods. This is a more robust version of our previous strategy of checking whether `currentlyRenderingFiber` is null. As a next step, we can use a separate dispatcher for each phase of the render cycle (mount versus update). * Use separate dispatchers for mount and update * Remove mount code from update path Deletes mount-specific code from the update path, since it should be unreachable. To continue supporting progressive enhancement (mounting new hooks at the end of the list), we detect when there are no more current hooks and switch back to the mount dispatcher. Progressive enhancement isn't officially supported yet, so it will continue to warn. * Factoring nits * Fix Flow Had to cheat more than I would like * More Flow nits * Switch back to using a special dispatcher for nested hooks in DEV In order for this strategy to work, I had to revert progressive enhancement support (appending hooks to the end). It was previously a warning but now it results in an error. We'll reconsider later. * Always pass args to updateState and updateReducer Even though the extra args are only used on mount, to ensure type consistency.
1 parent 9d483dc commit cb1ff43

10 files changed

+1001
-557
lines changed

packages/react-debug-tools/src/ReactDebugHooks.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import type {ReactContext, ReactProviderType} from 'shared/ReactTypes';
1111
import type {Fiber} from 'react-reconciler/src/ReactFiber';
1212
import type {Hook} from 'react-reconciler/src/ReactFiberHooks';
13-
import typeof {Dispatcher as DispatcherType} from 'react-reconciler/src/ReactFiberDispatcher';
13+
import type {Dispatcher as DispatcherType} from 'react-reconciler/src/ReactFiberHooks';
1414

1515
import ErrorStackParser from 'error-stack-parser';
1616
import ReactSharedInternals from 'shared/ReactSharedInternals';

packages/react-dom/src/__tests__/ReactDOMServerIntegrationHooks-test.internal.js

+17-13
Original file line numberDiff line numberDiff line change
@@ -432,21 +432,25 @@ describe('ReactDOMServerHooks', () => {
432432
expect(domNode.textContent).toEqual('hi');
433433
});
434434

435-
itRenders('with a warning for useRef inside useReducer', async render => {
436-
function App() {
437-
const [value, dispatch] = useReducer((state, action) => {
438-
useRef(0);
439-
return state + 1;
440-
}, 0);
441-
if (value === 0) {
442-
dispatch();
435+
itThrowsWhenRendering(
436+
'with a warning for useRef inside useReducer',
437+
async render => {
438+
function App() {
439+
const [value, dispatch] = useReducer((state, action) => {
440+
useRef(0);
441+
return state + 1;
442+
}, 0);
443+
if (value === 0) {
444+
dispatch();
445+
}
446+
return value;
443447
}
444-
return value;
445-
}
446448

447-
const domNode = await render(<App />, 1);
448-
expect(domNode.textContent).toEqual('1');
449-
});
449+
const domNode = await render(<App />, 1);
450+
expect(domNode.textContent).toEqual('1');
451+
},
452+
'Rendered more hooks than during the previous render',
453+
);
450454

451455
itRenders('with a warning for useRef inside useState', async render => {
452456
function App() {

packages/react-dom/src/server/ReactPartialRendererHooks.js

+4-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* @flow
88
*/
99

10-
import typeof {Dispatcher as DispatcherType} from 'react-reconciler/src/ReactFiberDispatcher';
10+
import type {Dispatcher as DispatcherType} from 'react-reconciler/src/ReactFiberHooks';
1111
import type {ThreadID} from './ReactThreadIDAllocator';
1212
import type {ReactContext} from 'shared/ReactTypes';
1313

@@ -113,6 +113,9 @@ function areHookInputsEqual(
113113
}
114114

115115
function createHook(): Hook {
116+
if (numberOfReRenders > 0) {
117+
invariant(false, 'Rendered more hooks than during the previous render');
118+
}
116119
return {
117120
memoizedState: null,
118121
queue: null,

packages/react-reconciler/src/ReactFiberDispatcher.js

-36
This file was deleted.

0 commit comments

Comments
 (0)