mirror of
https://github.com/facebook/react.git
synced 2025-11-01 09:12:30 +00:00
[Fresh] Support lazy() and add Suspense tests (#15681)
* Test that state is not leaked between components * Support lazy and add Suspense tests * Nits
This commit is contained in:
@@ -895,6 +895,592 @@ describe('ReactFresh', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('can preserve state for lazy after resolution', async () => {
|
||||
if (__DEV__) {
|
||||
let OuterV1 = render(() => {
|
||||
function Hello() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
__register__(Hello, 'Hello');
|
||||
|
||||
const Outer = React.lazy(
|
||||
() =>
|
||||
new Promise(resolve => {
|
||||
setTimeout(() => resolve({default: Hello}), 100);
|
||||
}),
|
||||
);
|
||||
__register__(Outer, 'Outer');
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<React.Suspense fallback={<p>Loading</p>}>
|
||||
<Outer />
|
||||
</React.Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
return App;
|
||||
});
|
||||
|
||||
expect(container.textContent).toBe('Loading');
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect(container.textContent).toBe('0');
|
||||
|
||||
// Bump the state before patching.
|
||||
const el = container.firstChild;
|
||||
expect(el.textContent).toBe('0');
|
||||
expect(el.style.color).toBe('blue');
|
||||
act(() => {
|
||||
el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
|
||||
});
|
||||
expect(el.textContent).toBe('1');
|
||||
|
||||
// Perform a hot update.
|
||||
patch(() => {
|
||||
function Hello() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
__register__(Hello, 'Hello');
|
||||
});
|
||||
|
||||
// Assert the state was preserved but color changed.
|
||||
expect(container.firstChild).toBe(el);
|
||||
expect(el.textContent).toBe('1');
|
||||
expect(el.style.color).toBe('red');
|
||||
|
||||
// Bump the state again.
|
||||
act(() => {
|
||||
el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
|
||||
});
|
||||
expect(container.firstChild).toBe(el);
|
||||
expect(el.textContent).toBe('2');
|
||||
expect(el.style.color).toBe('red');
|
||||
|
||||
// Perform a top-down render with a stale type.
|
||||
render(() => OuterV1);
|
||||
expect(container.firstChild).toBe(el);
|
||||
expect(el.textContent).toBe('2');
|
||||
expect(el.style.color).toBe('red');
|
||||
|
||||
// Finally, a render with incompatible type should reset it.
|
||||
render(() => {
|
||||
function Hello() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
__register__(Hello, 'Hello');
|
||||
|
||||
// Note: no lazy wrapper this time.
|
||||
return Hello;
|
||||
});
|
||||
|
||||
expect(container.firstChild).not.toBe(el);
|
||||
const newEl = container.firstChild;
|
||||
expect(newEl.textContent).toBe('0');
|
||||
expect(newEl.style.color).toBe('blue');
|
||||
}
|
||||
});
|
||||
|
||||
it('can patch lazy before resolution', async () => {
|
||||
if (__DEV__) {
|
||||
render(() => {
|
||||
function Hello() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
__register__(Hello, 'Hello');
|
||||
|
||||
const Outer = React.lazy(
|
||||
() =>
|
||||
new Promise(resolve => {
|
||||
setTimeout(() => resolve({default: Hello}), 100);
|
||||
}),
|
||||
);
|
||||
__register__(Outer, 'Outer');
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<React.Suspense fallback={<p>Loading</p>}>
|
||||
<Outer />
|
||||
</React.Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
return App;
|
||||
});
|
||||
|
||||
expect(container.textContent).toBe('Loading');
|
||||
|
||||
// Perform a hot update.
|
||||
patch(() => {
|
||||
function Hello() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
__register__(Hello, 'Hello');
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
// Expect different color on initial mount.
|
||||
const el = container.firstChild;
|
||||
expect(el.textContent).toBe('0');
|
||||
expect(el.style.color).toBe('red');
|
||||
|
||||
// Bump state.
|
||||
act(() => {
|
||||
el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
|
||||
});
|
||||
expect(container.firstChild).toBe(el);
|
||||
expect(el.textContent).toBe('1');
|
||||
expect(el.style.color).toBe('red');
|
||||
|
||||
// Test another reload.
|
||||
patch(() => {
|
||||
function Hello() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
__register__(Hello, 'Hello');
|
||||
});
|
||||
expect(container.firstChild).toBe(el);
|
||||
expect(el.textContent).toBe('1');
|
||||
expect(el.style.color).toBe('orange');
|
||||
}
|
||||
});
|
||||
|
||||
it('can patch lazy(forwardRef) before resolution', async () => {
|
||||
if (__DEV__) {
|
||||
render(() => {
|
||||
function renderHello() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
const Hello = React.forwardRef(renderHello);
|
||||
__register__(Hello, 'Hello');
|
||||
|
||||
const Outer = React.lazy(
|
||||
() =>
|
||||
new Promise(resolve => {
|
||||
setTimeout(() => resolve({default: Hello}), 100);
|
||||
}),
|
||||
);
|
||||
__register__(Outer, 'Outer');
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<React.Suspense fallback={<p>Loading</p>}>
|
||||
<Outer />
|
||||
</React.Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
return App;
|
||||
});
|
||||
|
||||
expect(container.textContent).toBe('Loading');
|
||||
|
||||
// Perform a hot update.
|
||||
patch(() => {
|
||||
function renderHello() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
const Hello = React.forwardRef(renderHello);
|
||||
__register__(Hello, 'Hello');
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
// Expect different color on initial mount.
|
||||
const el = container.firstChild;
|
||||
expect(el.textContent).toBe('0');
|
||||
expect(el.style.color).toBe('red');
|
||||
|
||||
// Bump state.
|
||||
act(() => {
|
||||
el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
|
||||
});
|
||||
expect(container.firstChild).toBe(el);
|
||||
expect(el.textContent).toBe('1');
|
||||
expect(el.style.color).toBe('red');
|
||||
|
||||
// Test another reload.
|
||||
patch(() => {
|
||||
function renderHello() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
const Hello = React.forwardRef(renderHello);
|
||||
__register__(Hello, 'Hello');
|
||||
});
|
||||
expect(container.firstChild).toBe(el);
|
||||
expect(el.textContent).toBe('1');
|
||||
expect(el.style.color).toBe('orange');
|
||||
}
|
||||
});
|
||||
|
||||
it('can patch lazy(memo) before resolution', async () => {
|
||||
if (__DEV__) {
|
||||
render(() => {
|
||||
function renderHello() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
const Hello = React.memo(renderHello);
|
||||
__register__(Hello, 'Hello');
|
||||
|
||||
const Outer = React.lazy(
|
||||
() =>
|
||||
new Promise(resolve => {
|
||||
setTimeout(() => resolve({default: Hello}), 100);
|
||||
}),
|
||||
);
|
||||
__register__(Outer, 'Outer');
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<React.Suspense fallback={<p>Loading</p>}>
|
||||
<Outer />
|
||||
</React.Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
return App;
|
||||
});
|
||||
|
||||
expect(container.textContent).toBe('Loading');
|
||||
|
||||
// Perform a hot update.
|
||||
patch(() => {
|
||||
function renderHello() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
const Hello = React.memo(renderHello);
|
||||
__register__(Hello, 'Hello');
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
// Expect different color on initial mount.
|
||||
const el = container.firstChild;
|
||||
expect(el.textContent).toBe('0');
|
||||
expect(el.style.color).toBe('red');
|
||||
|
||||
// Bump state.
|
||||
act(() => {
|
||||
el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
|
||||
});
|
||||
expect(container.firstChild).toBe(el);
|
||||
expect(el.textContent).toBe('1');
|
||||
expect(el.style.color).toBe('red');
|
||||
|
||||
// Test another reload.
|
||||
patch(() => {
|
||||
function renderHello() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
const Hello = React.memo(renderHello);
|
||||
__register__(Hello, 'Hello');
|
||||
});
|
||||
expect(container.firstChild).toBe(el);
|
||||
expect(el.textContent).toBe('1');
|
||||
expect(el.style.color).toBe('orange');
|
||||
}
|
||||
});
|
||||
|
||||
it('can patch lazy(memo(forwardRef)) before resolution', async () => {
|
||||
if (__DEV__) {
|
||||
render(() => {
|
||||
function renderHello() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
const Hello = React.memo(React.forwardRef(renderHello));
|
||||
__register__(Hello, 'Hello');
|
||||
|
||||
const Outer = React.lazy(
|
||||
() =>
|
||||
new Promise(resolve => {
|
||||
setTimeout(() => resolve({default: Hello}), 100);
|
||||
}),
|
||||
);
|
||||
__register__(Outer, 'Outer');
|
||||
|
||||
function App() {
|
||||
return (
|
||||
<React.Suspense fallback={<p>Loading</p>}>
|
||||
<Outer />
|
||||
</React.Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
return App;
|
||||
});
|
||||
|
||||
expect(container.textContent).toBe('Loading');
|
||||
|
||||
// Perform a hot update.
|
||||
patch(() => {
|
||||
function renderHello() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
const Hello = React.memo(React.forwardRef(renderHello));
|
||||
__register__(Hello, 'Hello');
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
// Expect different color on initial mount.
|
||||
const el = container.firstChild;
|
||||
expect(el.textContent).toBe('0');
|
||||
expect(el.style.color).toBe('red');
|
||||
|
||||
// Bump state.
|
||||
act(() => {
|
||||
el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
|
||||
});
|
||||
expect(container.firstChild).toBe(el);
|
||||
expect(el.textContent).toBe('1');
|
||||
expect(el.style.color).toBe('red');
|
||||
|
||||
// Test another reload.
|
||||
patch(() => {
|
||||
function renderHello() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
const Hello = React.memo(React.forwardRef(renderHello));
|
||||
__register__(Hello, 'Hello');
|
||||
});
|
||||
expect(container.firstChild).toBe(el);
|
||||
expect(el.textContent).toBe('1');
|
||||
expect(el.style.color).toBe('orange');
|
||||
}
|
||||
});
|
||||
|
||||
it('can patch both trees while suspense is displaying the fallback', async () => {
|
||||
if (__DEV__) {
|
||||
const AppV1 = render(
|
||||
() => {
|
||||
function Hello({children}) {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
|
||||
{children} {val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
__register__(Hello, 'Hello');
|
||||
|
||||
function Never() {
|
||||
throw new Promise(resolve => {});
|
||||
}
|
||||
|
||||
function App({shouldSuspend}) {
|
||||
return (
|
||||
<React.Suspense fallback={<Hello>Fallback</Hello>}>
|
||||
<Hello>Content</Hello>
|
||||
{shouldSuspend && <Never />}
|
||||
</React.Suspense>
|
||||
);
|
||||
}
|
||||
|
||||
return App;
|
||||
},
|
||||
{shouldSuspend: false},
|
||||
);
|
||||
|
||||
// We start with just the primary tree.
|
||||
expect(container.childNodes.length).toBe(1);
|
||||
const primaryChild = container.firstChild;
|
||||
expect(primaryChild.textContent).toBe('Content 0');
|
||||
expect(primaryChild.style.color).toBe('blue');
|
||||
expect(primaryChild.style.display).toBe('');
|
||||
|
||||
// Bump primary content state.
|
||||
act(() => {
|
||||
primaryChild.dispatchEvent(new MouseEvent('click', {bubbles: true}));
|
||||
});
|
||||
expect(container.childNodes.length).toBe(1);
|
||||
expect(container.childNodes[0]).toBe(primaryChild);
|
||||
expect(primaryChild.textContent).toBe('Content 1');
|
||||
expect(primaryChild.style.color).toBe('blue');
|
||||
expect(primaryChild.style.display).toBe('');
|
||||
|
||||
// Perform a hot update.
|
||||
patch(() => {
|
||||
function Hello({children}) {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'green'}} onClick={() => setVal(val + 1)}>
|
||||
{children} {val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
__register__(Hello, 'Hello');
|
||||
});
|
||||
expect(container.childNodes.length).toBe(1);
|
||||
expect(container.childNodes[0]).toBe(primaryChild);
|
||||
expect(primaryChild.textContent).toBe('Content 1');
|
||||
expect(primaryChild.style.color).toBe('green');
|
||||
expect(primaryChild.style.display).toBe('');
|
||||
|
||||
// Now force the tree to suspend.
|
||||
render(() => AppV1, {shouldSuspend: true});
|
||||
|
||||
// Expect to see two trees, one of them is hidden.
|
||||
expect(container.childNodes.length).toBe(2);
|
||||
expect(container.childNodes[0]).toBe(primaryChild);
|
||||
const fallbackChild = container.childNodes[1];
|
||||
expect(primaryChild.textContent).toBe('Content 1');
|
||||
expect(primaryChild.style.color).toBe('green');
|
||||
expect(primaryChild.style.display).toBe('none');
|
||||
expect(fallbackChild.textContent).toBe('Fallback 0');
|
||||
expect(fallbackChild.style.color).toBe('green');
|
||||
expect(fallbackChild.style.display).toBe('');
|
||||
|
||||
// Bump fallback state.
|
||||
act(() => {
|
||||
fallbackChild.dispatchEvent(new MouseEvent('click', {bubbles: true}));
|
||||
});
|
||||
expect(container.childNodes.length).toBe(2);
|
||||
expect(container.childNodes[0]).toBe(primaryChild);
|
||||
expect(container.childNodes[1]).toBe(fallbackChild);
|
||||
expect(primaryChild.textContent).toBe('Content 1');
|
||||
expect(primaryChild.style.color).toBe('green');
|
||||
expect(primaryChild.style.display).toBe('none');
|
||||
expect(fallbackChild.textContent).toBe('Fallback 1');
|
||||
expect(fallbackChild.style.color).toBe('green');
|
||||
expect(fallbackChild.style.display).toBe('');
|
||||
|
||||
// Perform a hot update.
|
||||
patch(() => {
|
||||
function Hello({children}) {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
|
||||
{children} {val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
__register__(Hello, 'Hello');
|
||||
});
|
||||
|
||||
// Colors inside both trees should change:
|
||||
expect(container.childNodes.length).toBe(2);
|
||||
expect(container.childNodes[0]).toBe(primaryChild);
|
||||
expect(container.childNodes[1]).toBe(fallbackChild);
|
||||
expect(primaryChild.textContent).toBe('Content 1');
|
||||
expect(primaryChild.style.color).toBe('red');
|
||||
expect(primaryChild.style.display).toBe('none');
|
||||
expect(fallbackChild.textContent).toBe('Fallback 1');
|
||||
expect(fallbackChild.style.color).toBe('red');
|
||||
expect(fallbackChild.style.display).toBe('');
|
||||
|
||||
// Only primary tree should exist now:
|
||||
render(() => AppV1, {shouldSuspend: false});
|
||||
expect(container.childNodes.length).toBe(1);
|
||||
expect(container.childNodes[0]).toBe(primaryChild);
|
||||
expect(primaryChild.textContent).toBe('Content 1');
|
||||
expect(primaryChild.style.color).toBe('red');
|
||||
expect(primaryChild.style.display).toBe('');
|
||||
|
||||
// Perform a hot update.
|
||||
patch(() => {
|
||||
function Hello({children}) {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'orange'}} onClick={() => setVal(val + 1)}>
|
||||
{children} {val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
__register__(Hello, 'Hello');
|
||||
});
|
||||
expect(container.childNodes.length).toBe(1);
|
||||
expect(container.childNodes[0]).toBe(primaryChild);
|
||||
expect(primaryChild.textContent).toBe('Content 1');
|
||||
expect(primaryChild.style.color).toBe('orange');
|
||||
expect(primaryChild.style.display).toBe('');
|
||||
}
|
||||
});
|
||||
|
||||
it('does not re-render ancestor components unnecessarily during a hot update', () => {
|
||||
if (__DEV__) {
|
||||
let appRenders = 0;
|
||||
@@ -963,6 +1549,96 @@ describe('ReactFresh', () => {
|
||||
}
|
||||
});
|
||||
|
||||
it('does not leak state between components', () => {
|
||||
if (__DEV__) {
|
||||
const AppV1 = render(
|
||||
() => {
|
||||
function Hello1() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
__register__(Hello1, 'Hello1');
|
||||
function Hello2() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'blue'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
__register__(Hello2, 'Hello2');
|
||||
function App({cond}) {
|
||||
return cond ? <Hello1 /> : <Hello2 />;
|
||||
}
|
||||
__register__(App, 'App');
|
||||
return App;
|
||||
},
|
||||
{cond: false},
|
||||
);
|
||||
|
||||
// Bump the state before patching.
|
||||
const el = container.firstChild;
|
||||
expect(el.textContent).toBe('0');
|
||||
expect(el.style.color).toBe('blue');
|
||||
act(() => {
|
||||
el.dispatchEvent(new MouseEvent('click', {bubbles: true}));
|
||||
});
|
||||
expect(el.textContent).toBe('1');
|
||||
|
||||
// Switch the condition, flipping inner content.
|
||||
// This should reset the state.
|
||||
render(() => AppV1, {cond: true});
|
||||
const el2 = container.firstChild;
|
||||
expect(el2).not.toBe(el);
|
||||
expect(el2.textContent).toBe('0');
|
||||
expect(el2.style.color).toBe('blue');
|
||||
|
||||
// Bump it again.
|
||||
act(() => {
|
||||
el2.dispatchEvent(new MouseEvent('click', {bubbles: true}));
|
||||
});
|
||||
expect(el2.textContent).toBe('1');
|
||||
|
||||
// Perform a hot update for both inner components.
|
||||
patch(() => {
|
||||
function Hello1() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
__register__(Hello1, 'Hello1');
|
||||
function Hello2() {
|
||||
const [val, setVal] = React.useState(0);
|
||||
return (
|
||||
<p style={{color: 'red'}} onClick={() => setVal(val + 1)}>
|
||||
{val}
|
||||
</p>
|
||||
);
|
||||
}
|
||||
__register__(Hello2, 'Hello2');
|
||||
});
|
||||
|
||||
// Assert the state was preserved but color changed.
|
||||
expect(container.firstChild).toBe(el2);
|
||||
expect(el2.textContent).toBe('1');
|
||||
expect(el2.style.color).toBe('red');
|
||||
|
||||
// Flip the condition again.
|
||||
render(() => AppV1, {cond: false});
|
||||
const el3 = container.firstChild;
|
||||
expect(el3).not.toBe(el2);
|
||||
expect(el3.textContent).toBe('0');
|
||||
expect(el3.style.color).toBe('red');
|
||||
}
|
||||
});
|
||||
|
||||
it('can force remount by changing signature', () => {
|
||||
if (__DEV__) {
|
||||
let HelloV1 = render(() => {
|
||||
|
||||
+8
-3
@@ -1030,9 +1030,6 @@ function mountLazyComponent(
|
||||
// Cancel and resume right after we know the tag.
|
||||
cancelWorkTimer(workInProgress);
|
||||
let Component = readLazyComponentType(elementType);
|
||||
if (__DEV__) {
|
||||
// TODO: resolve type for hot reloading.
|
||||
}
|
||||
// Store the unwrapped component in the type.
|
||||
workInProgress.type = Component;
|
||||
const resolvedTag = (workInProgress.tag = resolveLazyComponentTag(Component));
|
||||
@@ -1043,6 +1040,9 @@ function mountLazyComponent(
|
||||
case FunctionComponent: {
|
||||
if (__DEV__) {
|
||||
validateFunctionComponentInDev(workInProgress, Component);
|
||||
workInProgress.type = Component = resolveFunctionForHotReloading(
|
||||
Component,
|
||||
);
|
||||
}
|
||||
child = updateFunctionComponent(
|
||||
null,
|
||||
@@ -1064,6 +1064,11 @@ function mountLazyComponent(
|
||||
break;
|
||||
}
|
||||
case ForwardRef: {
|
||||
if (__DEV__) {
|
||||
workInProgress.type = Component = resolveFunctionForHotReloading(
|
||||
Component,
|
||||
);
|
||||
}
|
||||
child = updateForwardRef(
|
||||
null,
|
||||
workInProgress,
|
||||
|
||||
Reference in New Issue
Block a user