Don't ignore dependencies for render phase update (#16574)

This commit is contained in:
Dan Abramov
2019-08-28 16:55:56 +01:00
committed by GitHub
parent 1b585f630b
commit 01fb68b9bf
2 changed files with 48 additions and 0 deletions
+5
View File
@@ -428,6 +428,11 @@ export function renderWithHooks(
do {
didScheduleRenderPhaseUpdate = false;
numberOfReRenders += 1;
if (__DEV__) {
// Even when hot reloading, allow dependencies to stabilize
// after first render to prevent infinite render phase updates.
ignorePreviousDependencies = false;
}
// Start over from the beginning of the list
nextCurrentHook = current !== null ? current.memoizedState : null;
+43
View File
@@ -2350,6 +2350,49 @@ describe('ReactFresh', () => {
}
});
// This pattern is inspired by useSubscription and similar mechanisms.
it('does not get into infinite loops during render phase updates', () => {
if (__DEV__) {
render(() => {
function Hello() {
const source = React.useMemo(() => ({value: 10}), []);
const [state, setState] = React.useState({value: null});
if (state !== source) {
setState(source);
}
return <p style={{color: 'blue'}}>{state.value}</p>;
}
$RefreshReg$(Hello, 'Hello');
return Hello;
});
const el = container.firstChild;
expect(el.textContent).toBe('10');
expect(el.style.color).toBe('blue');
// Perform a hot update.
act(() => {
patch(() => {
function Hello() {
const source = React.useMemo(() => ({value: 20}), []);
const [state, setState] = React.useState({value: null});
if (state !== source) {
// This should perform a single render-phase update.
setState(source);
}
return <p style={{color: 'red'}}>{state.value}</p>;
}
$RefreshReg$(Hello, 'Hello');
return Hello;
});
});
expect(container.firstChild).toBe(el);
expect(el.textContent).toBe('20');
expect(el.style.color).toBe('red');
}
});
it('can hot reload offscreen components', () => {
if (__DEV__) {
const AppV1 = prepare(() => {