fix: Table render twice on first mount (#34106)

* fix: Table render twice

* chore: clean up

* test: Fix test case
This commit is contained in:
二货机器人 2022-02-17 18:11:33 +08:00 committed by GitHub
parent 106acb7d5b
commit 9f602aa710
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 33 additions and 519 deletions

View File

@ -1,18 +1,23 @@
import { useEffect, useState } from 'react';
import { useEffect, useRef } from 'react';
import useForceUpdate from '../../_util/hooks/useForceUpdate';
import ResponsiveObserve, { ScreenMap } from '../../_util/responsiveObserve';
function useBreakpoint(): ScreenMap {
const [screens, setScreens] = useState<ScreenMap>({});
function useBreakpoint(refreshOnChange: boolean = true): ScreenMap {
const screensRef = useRef<ScreenMap>({});
const forceUpdate = useForceUpdate();
useEffect(() => {
const token = ResponsiveObserve.subscribe(supportScreens => {
setScreens(supportScreens);
screensRef.current = supportScreens;
if (refreshOnChange) {
forceUpdate();
}
});
return () => ResponsiveObserve.unsubscribe(token);
}, []);
return screens;
return screensRef.current;
}
export default useBreakpoint;

View File

@ -139,15 +139,25 @@ function InternalTable<RecordType extends object = any>(
'`index` parameter of `rowKey` function is deprecated. There is no guarantee that it will work as expected.',
);
const screens = useBreakpoint();
const baseColumns = React.useMemo(
() => columns || convertChildrenToColumns(children),
[columns, children],
);
const needResponsive = React.useMemo(
() => baseColumns.some((col: ColumnType<RecordType>) => col.responsive),
[baseColumns],
);
const screens = useBreakpoint(needResponsive);
const mergedColumns = React.useMemo(() => {
const matched = new Set(Object.keys(screens).filter((m: Breakpoint) => screens[m]));
return (columns || convertChildrenToColumns(children)).filter(
return baseColumns.filter(
(c: ColumnType<RecordType>) =>
!c.responsive || c.responsive.some((r: Breakpoint) => matched.has(r)),
);
}, [children, columns, screens]);
}, [baseColumns, screens]);
const tableProps = omit(props, ['className', 'style', 'columns']) as TableProps<RecordType>;

View File

@ -1100,7 +1100,7 @@ describe('Table.filter', () => {
it('should support getPopupContainer', () => {
const getPopupContainer = jest.fn(node => node.parentNode);
const wrapper = mount(
mount(
createTable({
columns: [
{
@ -1111,13 +1111,14 @@ describe('Table.filter', () => {
getPopupContainer,
}),
);
expect(wrapper.render()).toMatchSnapshot();
expect(getPopupContainer).toHaveBeenCalled();
});
it('should support getPopupContainer from ConfigProvider', () => {
const wrapper = mount(
<ConfigProvider getPopupContainer={node => node.parentNode}>
const getPopupContainer = jest.fn(node => node.parentNode);
mount(
<ConfigProvider getPopupContainer={getPopupContainer}>
{createTable({
columns: [
{
@ -1128,7 +1129,7 @@ describe('Table.filter', () => {
})}
</ConfigProvider>,
);
expect(wrapper.render()).toMatchSnapshot();
expect(getPopupContainer).toHaveBeenCalled();
});
it('pass visible prop to filterDropdown', () => {

View File

@ -509,507 +509,3 @@ exports[`Table.filter renders filter correctly 1`] = `
exports[`Table.filter renders menu correctly 1`] = `<div />`;
exports[`Table.filter renders radio filter correctly 1`] = `<div />`;
exports[`Table.filter should support getPopupContainer 1`] = `
<div
class="ant-table-wrapper"
>
<div
class="ant-spin-nested-loading"
>
<div
class="ant-spin-container"
>
<div
class="ant-table"
>
<div
class="ant-table-container"
>
<div
class="ant-table-content"
>
<table
style="table-layout: auto;"
>
<colgroup />
<thead
class="ant-table-thead"
>
<tr>
<th
class="ant-table-cell"
>
<div
class="ant-table-filter-column"
>
<span
class="ant-table-column-title"
>
Name
</span>
<span
class="ant-dropdown-trigger ant-table-filter-trigger ant-dropdown-open"
role="button"
tabindex="-1"
>
<span
aria-label="filter"
class="anticon anticon-filter"
role="img"
>
<svg
aria-hidden="true"
data-icon="filter"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M349 838c0 17.7 14.2 32 31.8 32h262.4c17.6 0 31.8-14.3 31.8-32V642H349v196zm531.1-684H143.9c-24.5 0-39.8 26.7-27.5 48l221.3 376h348.8l221.3-376c12.1-21.3-3.2-48-27.7-48z"
/>
</svg>
</span>
</span>
<div>
<div
class="ant-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up"
style="opacity: 0; pointer-events: none;"
>
<div
class="ant-table-filter-dropdown"
>
<ul
class="ant-dropdown-menu ant-dropdown-menu-root ant-dropdown-menu-vertical ant-dropdown-menu-light"
data-menu-list="true"
role="menu"
tabindex="0"
>
<li
class="ant-dropdown-menu-item"
data-menu-id="rc-menu-uuid-test-boy"
role="menuitem"
tabindex="-1"
>
<span
class="ant-dropdown-menu-title-content"
>
<label
class="ant-checkbox-wrapper"
>
<span
class="ant-checkbox"
>
<input
class="ant-checkbox-input"
type="checkbox"
value=""
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
<span>
Boy
</span>
</span>
</li>
<li
class="ant-dropdown-menu-item"
data-menu-id="rc-menu-uuid-test-girl"
role="menuitem"
tabindex="-1"
>
<span
class="ant-dropdown-menu-title-content"
>
<label
class="ant-checkbox-wrapper"
>
<span
class="ant-checkbox"
>
<input
class="ant-checkbox-input"
type="checkbox"
value=""
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
<span>
Girl
</span>
</span>
</li>
<li
class="ant-dropdown-menu-submenu ant-dropdown-menu-submenu-vertical"
role="none"
>
<div
aria-controls="rc-menu-uuid-test-title-popup"
aria-expanded="false"
aria-haspopup="true"
class="ant-dropdown-menu-submenu-title"
data-menu-id="rc-menu-uuid-test-title"
role="menuitem"
tabindex="-1"
>
<span
class="ant-dropdown-menu-title-content"
>
Title
</span>
<i
class="ant-dropdown-menu-submenu-arrow"
/>
</div>
</li>
</ul>
<div
aria-hidden="true"
style="display: none;"
/>
<div
class="ant-table-filter-dropdown-btns"
>
<button
class="ant-btn ant-btn-link ant-btn-sm"
disabled=""
type="button"
>
<span>
Reset
</span>
</button>
<button
class="ant-btn ant-btn-primary ant-btn-sm"
type="button"
>
<span>
OK
</span>
</button>
</div>
</div>
</div>
</div>
<div
style="position: absolute; top: 0px; left: 0px; width: 100%;"
/>
<div
style="position: absolute; top: 0px; left: 0px; width: 100%;"
/>
</div>
</th>
</tr>
</thead>
<tbody
class="ant-table-tbody"
>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="0"
>
<td
class="ant-table-cell"
>
Jack
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="1"
>
<td
class="ant-table-cell"
>
Lucy
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="2"
>
<td
class="ant-table-cell"
>
Tom
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="3"
>
<td
class="ant-table-cell"
>
Jerry
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
`;
exports[`Table.filter should support getPopupContainer from ConfigProvider 1`] = `
<div
class="ant-table-wrapper"
>
<div
class="ant-spin-nested-loading"
>
<div
class="ant-spin-container"
>
<div
class="ant-table"
>
<div
class="ant-table-container"
>
<div
class="ant-table-content"
>
<table
style="table-layout: auto;"
>
<colgroup />
<thead
class="ant-table-thead"
>
<tr>
<th
class="ant-table-cell"
>
<div
class="ant-table-filter-column"
>
<span
class="ant-table-column-title"
>
Name
</span>
<span
class="ant-dropdown-trigger ant-table-filter-trigger ant-dropdown-open"
role="button"
tabindex="-1"
>
<span
aria-label="filter"
class="anticon anticon-filter"
role="img"
>
<svg
aria-hidden="true"
data-icon="filter"
fill="currentColor"
focusable="false"
height="1em"
viewBox="64 64 896 896"
width="1em"
>
<path
d="M349 838c0 17.7 14.2 32 31.8 32h262.4c17.6 0 31.8-14.3 31.8-32V642H349v196zm531.1-684H143.9c-24.5 0-39.8 26.7-27.5 48l221.3 376h348.8l221.3-376c12.1-21.3-3.2-48-27.7-48z"
/>
</svg>
</span>
</span>
<div>
<div
class="ant-dropdown ant-slide-up-appear ant-slide-up-appear-prepare ant-slide-up"
style="opacity: 0; pointer-events: none;"
>
<div
class="ant-table-filter-dropdown"
>
<ul
class="ant-dropdown-menu ant-dropdown-menu-root ant-dropdown-menu-vertical ant-dropdown-menu-light"
data-menu-list="true"
role="menu"
tabindex="0"
>
<li
class="ant-dropdown-menu-item"
data-menu-id="rc-menu-uuid-test-boy"
role="menuitem"
tabindex="-1"
>
<span
class="ant-dropdown-menu-title-content"
>
<label
class="ant-checkbox-wrapper"
>
<span
class="ant-checkbox"
>
<input
class="ant-checkbox-input"
type="checkbox"
value=""
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
<span>
Boy
</span>
</span>
</li>
<li
class="ant-dropdown-menu-item"
data-menu-id="rc-menu-uuid-test-girl"
role="menuitem"
tabindex="-1"
>
<span
class="ant-dropdown-menu-title-content"
>
<label
class="ant-checkbox-wrapper"
>
<span
class="ant-checkbox"
>
<input
class="ant-checkbox-input"
type="checkbox"
value=""
/>
<span
class="ant-checkbox-inner"
/>
</span>
</label>
<span>
Girl
</span>
</span>
</li>
<li
class="ant-dropdown-menu-submenu ant-dropdown-menu-submenu-vertical"
role="none"
>
<div
aria-controls="rc-menu-uuid-test-title-popup"
aria-expanded="false"
aria-haspopup="true"
class="ant-dropdown-menu-submenu-title"
data-menu-id="rc-menu-uuid-test-title"
role="menuitem"
tabindex="-1"
>
<span
class="ant-dropdown-menu-title-content"
>
Title
</span>
<i
class="ant-dropdown-menu-submenu-arrow"
/>
</div>
</li>
</ul>
<div
aria-hidden="true"
style="display: none;"
/>
<div
class="ant-table-filter-dropdown-btns"
>
<button
class="ant-btn ant-btn-link ant-btn-sm"
disabled=""
type="button"
>
<span>
Reset
</span>
</button>
<button
class="ant-btn ant-btn-primary ant-btn-sm"
type="button"
>
<span>
OK
</span>
</button>
</div>
</div>
</div>
</div>
<div
style="position: absolute; top: 0px; left: 0px; width: 100%;"
/>
<div
style="position: absolute; top: 0px; left: 0px; width: 100%;"
/>
</div>
</th>
</tr>
</thead>
<tbody
class="ant-table-tbody"
>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="0"
>
<td
class="ant-table-cell"
>
Jack
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="1"
>
<td
class="ant-table-cell"
>
Lucy
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="2"
>
<td
class="ant-table-cell"
>
Tom
</td>
</tr>
<tr
class="ant-table-row ant-table-row-level-0"
data-row-key="3"
>
<td
class="ant-table-cell"
>
Jerry
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>
</div>
`;

View File

@ -33,6 +33,8 @@ export const SELECTION_ALL = 'SELECT_ALL' as const;
export const SELECTION_INVERT = 'SELECT_INVERT' as const;
export const SELECTION_NONE = 'SELECT_NONE' as const;
const EMPTY_LIST: React.Key[] = [];
interface UseSelectionConfig<RecordType> {
prefixCls: string;
pageData: RecordType[];
@ -108,7 +110,7 @@ export default function useSelection<RecordType>(
// ========================= Keys =========================
const [mergedSelectedKeys, setMergedSelectedKeys] = useMergedState(
selectedRowKeys || defaultSelectedRowKeys || [],
selectedRowKeys || defaultSelectedRowKeys || EMPTY_LIST,
{
value: selectedRowKeys,
},
@ -215,7 +217,7 @@ export default function useSelection<RecordType>(
// Reset if rowSelection reset
React.useEffect(() => {
if (!rowSelection) {
setMergedSelectedKeys([]);
setMergedSelectedKeys(EMPTY_LIST);
}
}, [!!rowSelection]);