(Go: >> BACK << -|- >> HOME <<)

Skip to content

Commit

Permalink
fix: transfer error when reset data in some cases
Browse files Browse the repository at this point in the history
  • Loading branch information
committed Jun 1, 2023
1 parent b9db39d commit fe08ed8
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 1 deletion.
72 changes: 71 additions & 1 deletion components/transfer/__tests__/index.test.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import { fireEvent, render, waitFor } from '@testing-library/react';
import React, { useState } from 'react';
import { DefaultRecordType } from 'rc-table/lib/interface';

Check warning on line 2 in components/transfer/__tests__/index.test.tsx

View check run for this annotation

codefactor.io / CodeFactor

components/transfer/__tests__/index.test.tsx#L2

All imports in the declaration are only used as types. Use `import type`. (@typescript-eslint/consistent-type-imports)

Check failure on line 2 in components/transfer/__tests__/index.test.tsx

View workflow job for this annotation

GitHub Actions / lint

All imports in the declaration are only used as types. Use `import type`
import React, { useEffect, useState } from 'react';
import type { SelectAllLabel, TransferProps } from '..';
import Transfer from '..';
import mountTest from '../../../tests/shared/mountTest';
import rtlTest from '../../../tests/shared/rtlTest';
import Button from '../../button';

const consoleErrorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});

Expand Down Expand Up @@ -621,4 +623,72 @@ describe('immutable data', () => {
const { container } = render(<Transfer rowKey={(item) => item.id} dataSource={mockData} />);
expect(container.firstChild).toMatchSnapshot();
});

it('prevent error when reset data in some cases', () => {
const App = () => {
const [mockData, setMockData] = useState<DefaultRecordType[]>([]);
const [targetKeys, setTargetKeys] = useState<string[]>([]);

const getMock = () => {
const tempTargetKeys = [];
const tempMockData = [];
for (let i = 0; i < 2; i++) {
const data = {
key: i.toString(),
title: `content${i + 1}`,
description: `description of content${i + 1}`,
chosen: i % 2 === 0,
};
if (data.chosen) {
tempTargetKeys.push(data.key);
}
tempMockData.push(data);
}
setMockData(tempMockData);
setTargetKeys(tempTargetKeys);
};

useEffect(() => {
getMock();
}, []);

const handleChange = (newTargetKeys: string[]) => {
setTargetKeys(newTargetKeys);
};

return (
<>

Check warning on line 660 in components/transfer/__tests__/index.test.tsx

View check run for this annotation

codefactor.io / CodeFactor

components/transfer/__tests__/index.test.tsx#L660

Fragments should contain more than one child - otherwise, there’s no need for a Fragment at all. (react/jsx-no-useless-fragment)

Check failure on line 660 in components/transfer/__tests__/index.test.tsx

View workflow job for this annotation

GitHub Actions / lint

Fragments should contain more than one child - otherwise, there’s no need for a Fragment at all
<Transfer
dataSource={mockData}
operations={['to right', 'to left']}
targetKeys={targetKeys}
onChange={handleChange}
render={(item) => `test-${item}`}
footer={() => <Button onClick={getMock}>Right button reload</Button>}

Check warning on line 667 in components/transfer/__tests__/index.test.tsx

View check run for this annotation

codefactor.io / CodeFactor

components/transfer/__tests__/index.test.tsx#L667

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props. If you want to allow component creation in props, set allowAsProps option to true. (react/no-unstable-nested-components)

Check failure on line 667 in components/transfer/__tests__/index.test.tsx

View workflow job for this annotation

GitHub Actions / lint

Do not define components during render. React will see a new component type on every render and destroy the entire subtree’s DOM nodes and state (https://reactjs.org/docs/reconciliation.html#elements-of-different-types). Instead, move this component definition out of the parent component “App” and pass data as props. If you want to allow component creation in props, set allowAsProps option to true
/>
</>
);
};

const { container } = render(<App />);
fireEvent.click(container.querySelector('.ant-transfer-list-header input[type="checkbox"]')!);
fireEvent.click(container.querySelector('.ant-transfer-operation .ant-btn')!);
expect(container.querySelectorAll('.ant-transfer-list')[1]).toBeTruthy();
expect(
container
.querySelectorAll('.ant-transfer-list')[1]
.querySelectorAll('.ant-transfer-list-content-item').length,
).toBe(2);

fireEvent.click(
container.querySelectorAll('.ant-transfer-list-header input[type="checkbox"]')![1],
);
expect(container.querySelectorAll('.ant-transfer-list-header-selected')[1]).toContainHTML(
'2/2',
);
fireEvent.click(container.querySelector('.ant-transfer-list-footer .ant-btn')!);
expect(container.querySelectorAll('.ant-transfer-list-header-selected')[1]).toContainHTML(
'1/1',
);
});
});
13 changes: 13 additions & 0 deletions components/transfer/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,19 @@ const Transfer = <RecordType extends TransferItem = TransferItem>(
if (props.selectedKeys) {
setSourceSelectedKeys(() => selectedKeys.filter((key) => !targetKeys.includes(key)));
setTargetSelectedKeys(() => selectedKeys.filter((key) => targetKeys.includes(key)));
return;
}

// This is the calculation scheme when there are no props.selectedKeys
if (props.selectedKeys) {
setSourceSelectedKeys(() =>
props.targetKeys!.filter((key) => !sourceSelectedKeys.includes(key)),

Check warning on line 168 in components/transfer/index.tsx

View check run for this annotation

Codecov / codecov/patch

components/transfer/index.tsx#L167-L168

Added lines #L167 - L168 were not covered by tests
);
}
if (props.targetKeys) {
setTargetSelectedKeys(() =>
props.targetKeys!.filter((key) => targetSelectedKeys.includes(key)),
);
}
}, [props.selectedKeys, props.targetKeys]);

Expand Down

0 comments on commit fe08ed8

Please sign in to comment.