mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-27 20:49:53 +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;
|
||||
}
|
||||
|
||||
const rowContext = React.useMemo(() => ({ gutter: gutters, wrap, supportFlexGap }), [
|
||||
gutters,
|
||||
wrap,
|
||||
supportFlexGap,
|
||||
]);
|
||||
// "gutters" is a new array in each rendering phase, it'll make 'React.useMemo' effectless.
|
||||
// So we deconstruct "gutters" variable here.
|
||||
const [gutterH, gutterV] = gutters;
|
||||
const rowContext = React.useMemo(
|
||||
() => ({ gutter: [gutterH, gutterV] as [number, number], wrap, supportFlexGap }),
|
||||
[gutterH, gutterV, wrap, supportFlexGap],
|
||||
);
|
||||
|
||||
return (
|
||||
<RowContext.Provider value={rowContext}>
|
||||
|
@ -136,7 +136,7 @@ const Sider = React.forwardRef<HTMLDivElement, SiderProps>(
|
||||
mql?.removeListener(responsiveHandler);
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
}, [breakpoint]); // in order to accept dynamic 'breakpoint' property, we need to add 'breakpoint' into dependency array.
|
||||
|
||||
useEffect(() => {
|
||||
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