mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-24 11:10:01 +08:00
fix: Invalid hook dependency array in Sider and Row (#33804)
This commit is contained in:
parent
75adc23fe3
commit
fe23374871
48
components/grid/__tests__/cached-row-context.test.tsx
Normal file
48
components/grid/__tests__/cached-row-context.test.tsx
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
import React, { memo, useRef, useState, useContext } from 'react';
|
||||||
|
import { mount } from 'enzyme';
|
||||||
|
import Row from '../row';
|
||||||
|
import RowContext from '../RowContext';
|
||||||
|
|
||||||
|
const CacheInner = memo(() => {
|
||||||
|
const countRef = useRef(0);
|
||||||
|
countRef.current++;
|
||||||
|
useContext(RowContext);
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
Child Rendering Count: <span id="child_count">{countRef.current}</span>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
const CacheOuter = () => {
|
||||||
|
const [count, setCount] = useState(1);
|
||||||
|
const handleClick = () => {
|
||||||
|
setCount(count + 1);
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<button type="button" onClick={handleClick} id="parent_btn">
|
||||||
|
Click
|
||||||
|
</button>
|
||||||
|
Parent Rendering Count: <span id="parent_count">{count}</span>
|
||||||
|
<Row>
|
||||||
|
<CacheInner />
|
||||||
|
</Row>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
it('Cached RowContext is working', () => {
|
||||||
|
const wrapper = mount(<CacheOuter />);
|
||||||
|
const childCount = wrapper.find('#child_count').text();
|
||||||
|
|
||||||
|
wrapper.find('#parent_btn').at(0).simulate('click');
|
||||||
|
expect(wrapper.find('#parent_count').text()).toBe('2');
|
||||||
|
// child component won't rerender
|
||||||
|
expect(wrapper.find('#child_count').text()).toBe(childCount);
|
||||||
|
|
||||||
|
wrapper.find('#parent_btn').at(0).simulate('click');
|
||||||
|
expect(wrapper.find('#parent_count').text()).toBe('3');
|
||||||
|
// child component won't rerender
|
||||||
|
expect(wrapper.find('#child_count').text()).toBe(childCount);
|
||||||
|
});
|
@ -116,11 +116,13 @@ const Row = React.forwardRef<HTMLDivElement, RowProps>((props, ref) => {
|
|||||||
rowStyle.marginBottom = verticalGutter;
|
rowStyle.marginBottom = verticalGutter;
|
||||||
}
|
}
|
||||||
|
|
||||||
const rowContext = React.useMemo(() => ({ gutter: gutters, wrap, supportFlexGap }), [
|
// "gutters" is a new array in each rendering phase, it'll make 'React.useMemo' effectless.
|
||||||
gutters,
|
// So we deconstruct "gutters" variable here.
|
||||||
wrap,
|
const [gutterH, gutterV] = gutters;
|
||||||
supportFlexGap,
|
const rowContext = React.useMemo(
|
||||||
]);
|
() => ({ gutter: [gutterH, gutterV] as [number, number], wrap, supportFlexGap }),
|
||||||
|
[gutterH, gutterV, wrap, supportFlexGap],
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<RowContext.Provider value={rowContext}>
|
<RowContext.Provider value={rowContext}>
|
||||||
|
@ -136,7 +136,7 @@ const Sider = React.forwardRef<HTMLDivElement, SiderProps>(
|
|||||||
mql?.removeListener(responsiveHandler);
|
mql?.removeListener(responsiveHandler);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}, []);
|
}, [breakpoint]); // in order to accept dynamic 'breakpoint' property, we need to add 'breakpoint' into dependency array.
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const uniqueId = generateId('ant-sider-');
|
const uniqueId = generateId('ant-sider-');
|
||||||
|
47
components/layout/__tests__/dynamic-breakpoint.test.tsx
Normal file
47
components/layout/__tests__/dynamic-breakpoint.test.tsx
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
import React, { useState } from 'react';
|
||||||
|
import { mount } from 'enzyme';
|
||||||
|
import Sider from '../Sider';
|
||||||
|
|
||||||
|
const Content = () => {
|
||||||
|
const [breakpoint, setBreakpoint] = useState('sm');
|
||||||
|
const toggleBreakpoint = () => {
|
||||||
|
if (breakpoint === 'sm') {
|
||||||
|
setBreakpoint('lg');
|
||||||
|
} else {
|
||||||
|
setBreakpoint('sm');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return (
|
||||||
|
<Sider breakpoint={breakpoint as any}>
|
||||||
|
<button type="button" id="toggle" onClick={toggleBreakpoint}>
|
||||||
|
Toggle
|
||||||
|
</button>
|
||||||
|
</Sider>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
it('Dynamic breakpoint in Sider component', () => {
|
||||||
|
const add = jest.fn();
|
||||||
|
const remove = jest.fn();
|
||||||
|
jest.spyOn(window, 'matchMedia').mockReturnValue({
|
||||||
|
matches: true,
|
||||||
|
addEventListener: add,
|
||||||
|
removeEventListener: remove,
|
||||||
|
} as any);
|
||||||
|
|
||||||
|
const wrapper = mount(<Content />);
|
||||||
|
const newMatch = window.matchMedia as jest.Mock;
|
||||||
|
|
||||||
|
// subscribe at first
|
||||||
|
expect(newMatch.mock.calls.length).toBe(1);
|
||||||
|
expect(add.mock.calls.length).toBe(1);
|
||||||
|
expect(remove.mock.calls.length).toBe(0);
|
||||||
|
|
||||||
|
wrapper.find('#toggle').at(0).simulate('click');
|
||||||
|
// unsubscribe then subscribe again
|
||||||
|
expect(newMatch.mock.calls.length).toBe(2);
|
||||||
|
expect(add.mock.calls.length).toBe(2);
|
||||||
|
expect(remove.mock.calls.length).toBe(1);
|
||||||
|
|
||||||
|
jest.restoreAllMocks();
|
||||||
|
});
|
Loading…
Reference in New Issue
Block a user