mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[Blocks] Fix stale data on updates (#18810)
* [Blocks] Failing test for nested load * Simplify the test * Add a similar test that fails in PROD * Copy .type when cloning work in progress
This commit is contained in:
@@ -282,6 +282,8 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
|
||||
current.alternate = workInProgress;
|
||||
} else {
|
||||
workInProgress.pendingProps = pendingProps;
|
||||
// Needed because Blocks store data on type.
|
||||
workInProgress.type = current.type;
|
||||
|
||||
// We already have an alternate.
|
||||
// Reset the effect tag.
|
||||
@@ -415,6 +417,8 @@ export function resetWorkInProgress(workInProgress: Fiber, renderLanes: Lanes) {
|
||||
workInProgress.memoizedProps = current.memoizedProps;
|
||||
workInProgress.memoizedState = current.memoizedState;
|
||||
workInProgress.updateQueue = current.updateQueue;
|
||||
// Needed because Blocks store data on type.
|
||||
workInProgress.type = current.type;
|
||||
|
||||
// Clone the dependencies object. This is mutated during the render phase, so
|
||||
// it cannot be shared with the current fiber.
|
||||
|
||||
@@ -277,6 +277,8 @@ export function createWorkInProgress(current: Fiber, pendingProps: any): Fiber {
|
||||
current.alternate = workInProgress;
|
||||
} else {
|
||||
workInProgress.pendingProps = pendingProps;
|
||||
// Needed because Blocks store data on type.
|
||||
workInProgress.type = current.type;
|
||||
|
||||
// We already have an alternate.
|
||||
// Reset the effect tag.
|
||||
@@ -413,6 +415,8 @@ export function resetWorkInProgress(
|
||||
workInProgress.memoizedProps = current.memoizedProps;
|
||||
workInProgress.memoizedState = current.memoizedState;
|
||||
workInProgress.updateQueue = current.updateQueue;
|
||||
// Needed because Blocks store data on type.
|
||||
workInProgress.type = current.type;
|
||||
|
||||
// Clone the dependencies object. This is mutated during the render phase, so
|
||||
// it cannot be shared with the current fiber.
|
||||
|
||||
@@ -257,4 +257,87 @@ describe('ReactBlocks', () => {
|
||||
</>,
|
||||
);
|
||||
});
|
||||
|
||||
// Regression test.
|
||||
// @gate experimental
|
||||
it('does not render stale data after ping', async () => {
|
||||
function Child() {
|
||||
return <span>Name: {readString('Sebastian')}</span>;
|
||||
}
|
||||
|
||||
const loadParent = block(
|
||||
function Parent(props, data) {
|
||||
return (
|
||||
<Suspense fallback="Loading...">
|
||||
{data.name ? <Child /> : <span>Empty</span>}
|
||||
</Suspense>
|
||||
);
|
||||
},
|
||||
function load(name) {
|
||||
return {name};
|
||||
},
|
||||
);
|
||||
|
||||
function App({Page}) {
|
||||
return <Page />;
|
||||
}
|
||||
|
||||
await ReactNoop.act(async () => {
|
||||
ReactNoop.render(<App Page={loadParent(null)} />);
|
||||
});
|
||||
expect(ReactNoop).toMatchRenderedOutput(<span>Empty</span>);
|
||||
|
||||
await ReactNoop.act(async () => {
|
||||
ReactNoop.render(<App Page={loadParent('Sebastian')} />);
|
||||
});
|
||||
await ReactNoop.act(async () => {
|
||||
jest.advanceTimersByTime(1000);
|
||||
});
|
||||
expect(ReactNoop).toMatchRenderedOutput(<span>Name: Sebastian</span>);
|
||||
});
|
||||
|
||||
// Regression test.
|
||||
// @gate experimental
|
||||
it('does not render stale data after ping and setState', async () => {
|
||||
function Child() {
|
||||
return <span>Name: {readString('Sebastian')}</span>;
|
||||
}
|
||||
|
||||
let _setSuspend;
|
||||
const loadParent = block(
|
||||
function Parent(props, data) {
|
||||
const [suspend, setSuspend] = useState(true);
|
||||
_setSuspend = setSuspend;
|
||||
if (!suspend) {
|
||||
return <span>{data.name}</span>;
|
||||
}
|
||||
return (
|
||||
<Suspense fallback="Loading...">
|
||||
{data.name ? <Child /> : <span>Empty</span>}
|
||||
</Suspense>
|
||||
);
|
||||
},
|
||||
function load(name) {
|
||||
return {name};
|
||||
},
|
||||
);
|
||||
|
||||
function App({Page}) {
|
||||
return <Page />;
|
||||
}
|
||||
|
||||
await ReactNoop.act(async () => {
|
||||
ReactNoop.render(<App Page={loadParent(null)} />);
|
||||
});
|
||||
expect(ReactNoop).toMatchRenderedOutput(<span>Empty</span>);
|
||||
|
||||
await ReactNoop.act(async () => {
|
||||
ReactNoop.render(<App Page={loadParent('Sebastian')} />);
|
||||
});
|
||||
await ReactNoop.act(async () => {
|
||||
_setSuspend(false);
|
||||
jest.advanceTimersByTime(1000);
|
||||
});
|
||||
expect(ReactNoop).toMatchRenderedOutput(<span>Sebastian</span>);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user