mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-23 18:50:06 +08:00
Fix transfer selected keys (#51523)
* fix: transfer selected keys * test: add transfer test case * test: remove unused code * refactor: use cal data --------- Co-authored-by: karos <chenwenfan@harmonycloud.cn> Co-authored-by: 二货机器人 <smith3816@gmail.com>
This commit is contained in:
parent
77804ad1d4
commit
d80828ceff
@ -7,6 +7,7 @@ import Transfer from '..';
|
|||||||
import mountTest from '../../../tests/shared/mountTest';
|
import mountTest from '../../../tests/shared/mountTest';
|
||||||
import rtlTest from '../../../tests/shared/rtlTest';
|
import rtlTest from '../../../tests/shared/rtlTest';
|
||||||
import Button from '../../button';
|
import Button from '../../button';
|
||||||
|
import { waitFakeTimer } from '../../../tests/utils';
|
||||||
|
|
||||||
const listCommonProps: {
|
const listCommonProps: {
|
||||||
dataSource: { key: string; title: string; disabled?: boolean }[];
|
dataSource: { key: string; title: string; disabled?: boolean }[];
|
||||||
@ -767,6 +768,70 @@ describe('Transfer', () => {
|
|||||||
|
|
||||||
errSpy.mockRestore();
|
errSpy.mockRestore();
|
||||||
});
|
});
|
||||||
|
it('it checks correctly after changing the dataSource', async () => {
|
||||||
|
const mockData = Array.from({ length: 10 }).map((_, i) => ({
|
||||||
|
key: i.toString(),
|
||||||
|
title: `content${i + 1}`,
|
||||||
|
description: `description of content${i + 1}`,
|
||||||
|
}));
|
||||||
|
|
||||||
|
const initialTargetKeys = mockData
|
||||||
|
.filter((item) => Number(item.key) > 4)
|
||||||
|
.map((item) => item.key);
|
||||||
|
|
||||||
|
const defaultCheckedKeys = ['1', '2'];
|
||||||
|
const handleSelectChange = jest.fn();
|
||||||
|
const App: React.FC = () => {
|
||||||
|
const [targetKeys, setTargetKeys] = useState<TransferProps['targetKeys']>(initialTargetKeys);
|
||||||
|
const [selectedKeys, setSelectedKeys] = useState<TransferProps['targetKeys']>([]);
|
||||||
|
|
||||||
|
const [dataSource, setDataSource] = useState(mockData);
|
||||||
|
|
||||||
|
const onChange: TransferProps['onChange'] = (nextTargetKeys) => {
|
||||||
|
setTargetKeys(nextTargetKeys);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Button
|
||||||
|
className="update-btn"
|
||||||
|
onClick={() => {
|
||||||
|
setSelectedKeys(defaultCheckedKeys);
|
||||||
|
setDataSource([]);
|
||||||
|
setDataSource([...mockData]);
|
||||||
|
// setTimeout(() => {
|
||||||
|
// setDataSource([...mockData]);
|
||||||
|
// });
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
update
|
||||||
|
</Button>
|
||||||
|
<Transfer
|
||||||
|
dataSource={dataSource}
|
||||||
|
titles={['Source', 'Target']}
|
||||||
|
targetKeys={targetKeys}
|
||||||
|
selectedKeys={selectedKeys}
|
||||||
|
onChange={onChange}
|
||||||
|
onSelectChange={handleSelectChange}
|
||||||
|
render={(item) => item.title}
|
||||||
|
/>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
const { container } = render(<App />);
|
||||||
|
|
||||||
|
fireEvent.click(container.querySelector('.update-btn')!);
|
||||||
|
await waitFakeTimer();
|
||||||
|
|
||||||
|
defaultCheckedKeys.forEach((item) => {
|
||||||
|
expect(
|
||||||
|
container
|
||||||
|
?.querySelectorAll('.ant-transfer-list-content-item')
|
||||||
|
?.item(Number(item))
|
||||||
|
?.querySelector('input[type="checkbox"]')!,
|
||||||
|
).toBeChecked();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('immutable data', () => {
|
describe('immutable data', () => {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import * as React from 'react';
|
import * as React from 'react';
|
||||||
|
import { useEvent, useMergedState } from 'rc-util';
|
||||||
|
|
||||||
import type { TransferKey } from '../interface';
|
import type { TransferKey } from '../interface';
|
||||||
|
|
||||||
@ -16,12 +17,12 @@ function flattenKeys(keys: Set<TransferKey>) {
|
|||||||
export default function useSelection<T extends { key: TransferKey }>(
|
export default function useSelection<T extends { key: TransferKey }>(
|
||||||
leftDataSource: T[],
|
leftDataSource: T[],
|
||||||
rightDataSource: T[],
|
rightDataSource: T[],
|
||||||
selectedKeys: TransferKey[] = EMPTY_KEYS,
|
selectedKeys?: TransferKey[],
|
||||||
): [
|
): [
|
||||||
sourceSelectedKeys: TransferKey[],
|
sourceSelectedKeys: TransferKey[],
|
||||||
targetSelectedKeys: TransferKey[],
|
targetSelectedKeys: TransferKey[],
|
||||||
setSourceSelectedKeys: React.Dispatch<React.SetStateAction<TransferKey[]>>,
|
setSourceSelectedKeys: (srcKeys: TransferKey[]) => void,
|
||||||
setTargetSelectedKeys: React.Dispatch<React.SetStateAction<TransferKey[]>>,
|
setTargetSelectedKeys: (srcKeys: TransferKey[]) => void,
|
||||||
] {
|
] {
|
||||||
// Prepare `dataSource` keys
|
// Prepare `dataSource` keys
|
||||||
const [leftKeys, rightKeys] = React.useMemo(
|
const [leftKeys, rightKeys] = React.useMemo(
|
||||||
@ -33,25 +34,35 @@ export default function useSelection<T extends { key: TransferKey }>(
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Selected Keys
|
// Selected Keys
|
||||||
const [sourceSelectedKeys, setSourceSelectedKeys] = React.useState(() =>
|
const [mergedSelectedKeys, setMergedSelectedKeys] = useMergedState(EMPTY_KEYS, {
|
||||||
filterKeys(selectedKeys, leftKeys),
|
value: selectedKeys,
|
||||||
|
});
|
||||||
|
|
||||||
|
const sourceSelectedKeys = React.useMemo(
|
||||||
|
() => filterKeys(mergedSelectedKeys, leftKeys),
|
||||||
|
[mergedSelectedKeys, leftKeys],
|
||||||
);
|
);
|
||||||
const [targetSelectedKeys, setTargetSelectedKeys] = React.useState(() =>
|
const targetSelectedKeys = React.useMemo(
|
||||||
filterKeys(selectedKeys, rightKeys),
|
() => filterKeys(mergedSelectedKeys, rightKeys),
|
||||||
|
[mergedSelectedKeys, rightKeys],
|
||||||
);
|
);
|
||||||
|
|
||||||
// Fill selected keys
|
// // Reset when data changed
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
setSourceSelectedKeys(filterKeys(selectedKeys, leftKeys));
|
setMergedSelectedKeys([
|
||||||
setTargetSelectedKeys(filterKeys(selectedKeys, rightKeys));
|
...filterKeys(mergedSelectedKeys, leftKeys),
|
||||||
}, [selectedKeys]);
|
...filterKeys(mergedSelectedKeys, rightKeys),
|
||||||
|
]);
|
||||||
// Reset when data changed
|
|
||||||
React.useEffect(() => {
|
|
||||||
setSourceSelectedKeys(filterKeys(sourceSelectedKeys, leftKeys));
|
|
||||||
setTargetSelectedKeys(filterKeys(targetSelectedKeys, rightKeys));
|
|
||||||
}, [flattenKeys(leftKeys), flattenKeys(rightKeys)]);
|
}, [flattenKeys(leftKeys), flattenKeys(rightKeys)]);
|
||||||
|
|
||||||
|
// Update keys
|
||||||
|
const setSourceSelectedKeys = useEvent((nextSrcKeys: TransferKey[]) => {
|
||||||
|
setMergedSelectedKeys([...nextSrcKeys, ...targetSelectedKeys]);
|
||||||
|
});
|
||||||
|
const setTargetSelectedKeys = useEvent((nextTargetKeys: TransferKey[]) => {
|
||||||
|
setMergedSelectedKeys([...sourceSelectedKeys, ...nextTargetKeys]);
|
||||||
|
});
|
||||||
|
|
||||||
return [
|
return [
|
||||||
// Keys
|
// Keys
|
||||||
sourceSelectedKeys,
|
sourceSelectedKeys,
|
||||||
|
Loading…
Reference in New Issue
Block a user