Skip to content

Commit

Permalink
Transfer mounted effects on suspend in legacy mode
Browse files Browse the repository at this point in the history
In legacy mode, a component that suspends bails out and commit in
its previous state. If the component previously had mounted effects,
we must transfer those to the work-in-progress so they don't
get dropped.
  • Loading branch information
acdlite committed Mar 6, 2020
1 parent 8dea154 commit 4ddf4a5
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 0 deletions.
2 changes: 2 additions & 0 deletions packages/react-reconciler/src/ReactFiberThrow.js
Expand Up @@ -199,9 +199,11 @@ function throwException(
// to render it.
let currentSource = sourceFiber.alternate;
if (currentSource) {
sourceFiber.updateQueue = currentSource.updateQueue;
sourceFiber.memoizedState = currentSource.memoizedState;
sourceFiber.expirationTime = currentSource.expirationTime;
} else {
sourceFiber.updateQueue = null;
sourceFiber.memoizedState = null;
}
}
Expand Down
Expand Up @@ -1448,6 +1448,53 @@ function loadModules({
'Caught an error: Error in host config.',
);
});

it('does not drop mounted effects', async () => {
let never = {then() {}};

let setShouldSuspend;
function App() {
const [shouldSuspend, _setShouldSuspend] = React.useState(0);
setShouldSuspend = _setShouldSuspend;
return (
<Suspense fallback="Loading...">
<Child shouldSuspend={shouldSuspend} />
</Suspense>
);
}

function Child({shouldSuspend}) {
if (shouldSuspend === 1) {
throw never;
}

React.useEffect(() => {
Scheduler.unstable_yieldValue('Mount');
return () => {
Scheduler.unstable_yieldValue('Unmount');
};
}, []);

return 'Child';
}

const root = ReactNoop.createLegacyRoot(null);
await ReactNoop.act(async () => {
root.render(<App />);
});
expect(Scheduler).toHaveYielded(['Mount']);

// Suspend the child. This puts it into an inconsistent state.
await ReactNoop.act(async () => {
setShouldSuspend(true);
});

// Unmount everying
await ReactNoop.act(async () => {
root.render(null);
});
expect(Scheduler).toHaveYielded(['Unmount']);
});
});

it('does not call lifecycles of a suspended component', async () => {
Expand Down

0 comments on commit 4ddf4a5

Please sign in to comment.