Skip to content

Commit dfc9c2f

Browse files
author
willxywang
committed
fix: effect in memoed boundary should be re-executed when the lazy boundary resolves (#4631)
1 parent 1effaa6 commit dfc9c2f

File tree

2 files changed

+61
-4
lines changed

2 files changed

+61
-4
lines changed

compat/src/suspense.js

+3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ function detachedClone(vnode, detachedParent, parentDom) {
5757
if (vnode._component._parentDom === parentDom) {
5858
vnode._component._parentDom = detachedParent;
5959
}
60+
61+
vnode._component._force = true;
62+
6063
vnode._component = null;
6164
}
6265

compat/test/browser/suspense.test.js

+58-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { setupRerender } from 'preact/test-utils';
1+
import { act, setupRerender } from 'preact/test-utils';
22
import React, {
33
createElement,
44
render,
@@ -9,7 +9,8 @@ import React, {
99
createContext,
1010
useState,
1111
useEffect,
12-
useLayoutEffect
12+
useLayoutEffect,
13+
memo
1314
} from 'preact/compat';
1415
import { setupScratch, teardown } from '../../../test/_util/helpers';
1516
import { createLazy, createSuspender } from './suspense-utils';
@@ -1501,8 +1502,8 @@ describe('suspense', () => {
15011502

15021503
/** @type {() => void} */
15031504
let hide,
1504-
/** @type {(v) => void} */
1505-
setValue;
1505+
/** @type {(v) => void} */
1506+
setValue;
15061507

15071508
class Conditional extends Component {
15081509
constructor(props) {
@@ -2159,4 +2160,57 @@ describe('suspense', () => {
21592160
expect(scratch.innerHTML).to.equal('<div><p>hello world</p></div>');
21602161
});
21612162
});
2163+
2164+
it('should re-execute descendant memoed component effect when lazy boundary resolves', async () => {
2165+
const MemodComp = memo(() => {
2166+
const [state, setState] = useState('Memod effect not executed');
2167+
useEffect(() => {
2168+
setState('Memod effect executed');
2169+
}, []);
2170+
return <span>{state}</span>;
2171+
});
2172+
2173+
const NormalComp = () => {
2174+
const [state, setState] = useState('effect not executed');
2175+
useEffect(() => {
2176+
setState('effect executed');
2177+
}, []);
2178+
return <span>{state}</span>;
2179+
};
2180+
2181+
/** @type {() => Promise<void>} */
2182+
let resolve;
2183+
const LazyComp = lazy(() => {
2184+
const p = new Promise(res => {
2185+
resolve = () => {
2186+
res({ default: NormalComp });
2187+
return p;
2188+
};
2189+
});
2190+
2191+
return p;
2192+
});
2193+
2194+
render(
2195+
<Suspense fallback={<div>Suspended...</div>}>
2196+
<div>
2197+
<MemodComp />
2198+
<LazyComp />
2199+
</div>
2200+
</Suspense>,
2201+
scratch
2202+
);
2203+
2204+
rerender();
2205+
2206+
expect(scratch.innerHTML).to.eql(`<div>Suspended...</div>`);
2207+
2208+
await resolve();
2209+
2210+
await act(() => rerender());
2211+
2212+
return expect(scratch.innerHTML).to.eql(
2213+
`<div><span>Memod effect executed</span><span>effect executed</span></div>`
2214+
);
2215+
});
21622216
});

0 commit comments

Comments
 (0)