트랜스퍼
트랜스퍼 (Transfer)
두 컬럼 사이에서 항목을 직관적이고 효율적으로 이동시킬 수 있는 전송 컴포넌트입니다. 여러 항목을 선택하는 데 쓰여요.
출처: 문서
본문
언제 사용하나요 (When To Use)
- 본질적으로 여러 항목을 선택하는 데 사용할 수 있는 셀렉트 컨트롤입니다.
- Transfer는 항목에 대한 더 많은 정보를 표시할 수 있고 더 많은 공간을 차지합니다.
두 컬럼 사이에서 요소를 직관적이고 효율적으로 이동시킵니다.
어느 한 컬럼에서도 하나 이상의 요소를 선택할 수 있으며, 적절한 direction 버튼을 한 번 클릭하면 전송이 완료됩니다. 왼쪽 컬럼은 source, 오른쪽 컬럼은 target으로 간주됩니다. 이 이름들이 API에 반영되어 있는 것을 볼 수 있습니다.
참고: Transfer는 제어(controlled) 컴포넌트이며 비제어 모드는 지원하지 않습니다.
예제 (Examples)
기본 (Basic)
Transfer의 가장 기본적인 사용법은 소스 데이터와 타겟 키 배열, 렌더링, 그리고 일부 콜백 함수를 제공하는 것입니다.
import React, { useState } from 'react';
import { Transfer } from 'antd';
import type { TransferProps } from 'antd';
interface RecordType {
key: string;
title: string;
description: string;
}
const mockData = Array.from({ length: 20 }).map<RecordType>((_, i) => ({
key: i.toString(),
title: `content${i + 1}`,
description: `description of content${i + 1}`,
}));
const initialTargetKeys = mockData.filter((item) => Number(item.key) > 10).map((item) => item.key);
const App: React.FC = () => {
const [targetKeys, setTargetKeys] = useState<TransferProps['targetKeys']>(initialTargetKeys);
const [selectedKeys, setSelectedKeys] = useState<TransferProps['targetKeys']>([]);
const onChange: TransferProps['onChange'] = (nextTargetKeys, direction, moveKeys) => {
console.log('targetKeys:', nextTargetKeys);
console.log('direction:', direction);
console.log('moveKeys:', moveKeys);
setTargetKeys(nextTargetKeys);
};
const onSelectChange: TransferProps['onSelectChange'] = (
sourceSelectedKeys,
targetSelectedKeys,
) => {
console.log('sourceSelectedKeys:', sourceSelectedKeys);
console.log('targetSelectedKeys:', targetSelectedKeys);
setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys]);
};
const onScroll: TransferProps['onScroll'] = (direction, e) => {
console.log('direction:', direction);
console.log('target:', e.target);
};
return (
<Transfer
dataSource={mockData}
titles={['Source', 'Target']}
targetKeys={targetKeys}
selectedKeys={selectedKeys}
onChange={onChange}
onSelectChange={onSelectChange}
onScroll={onScroll}
render={(item) => item.title}
/>
);
};
export default App;
단방향 (One Way)
oneWay를 사용해 Transfer를 단방향 스타일로 만듭니다.
import React, { useState } from 'react';
import { Switch, Transfer } from 'antd';
import type { TransferProps } from 'antd';
interface RecordType {
key: string;
title: string;
description: string;
disabled: boolean;
}
const mockData = Array.from({ length: 20 }).map<RecordType>((_, i) => ({
key: i.toString(),
title: `content${i + 1}`,
description: `description of content${i + 1}`,
disabled: i % 3 < 1,
}));
const oriTargetKeys = mockData.filter((item) => Number(item.key) % 3 > 1).map((item) => item.key);
const App: React.FC = () => {
const [targetKeys, setTargetKeys] = useState<React.Key[]>(oriTargetKeys);
const [selectedKeys, setSelectedKeys] = useState<React.Key[]>([]);
const [disabled, setDisabled] = useState(false);
const handleChange: TransferProps['onChange'] = (newTargetKeys, direction, moveKeys) => {
setTargetKeys(newTargetKeys);
console.log('targetKeys: ', newTargetKeys);
console.log('direction: ', direction);
console.log('moveKeys: ', moveKeys);
};
const handleSelectChange: TransferProps['onSelectChange'] = (
sourceSelectedKeys,
targetSelectedKeys,
) => {
setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys]);
console.log('sourceSelectedKeys: ', sourceSelectedKeys);
console.log('targetSelectedKeys: ', targetSelectedKeys);
};
const handleScroll: TransferProps['onScroll'] = (direction, e) => {
console.log('direction:', direction);
console.log('target:', e.target);
};
const handleDisable = (checked: boolean) => {
setDisabled(checked);
};
return (
<>
<Transfer
dataSource={mockData}
titles={['Source', 'Target']}
targetKeys={targetKeys}
selectedKeys={selectedKeys}
onChange={handleChange}
onSelectChange={handleSelectChange}
onScroll={handleScroll}
render={(item) => item.title}
disabled={disabled}
oneWay
style={{ marginBottom: 16 }}
/>
<Switch
unCheckedChildren="disabled"
checkedChildren="disabled"
checked={disabled}
onChange={handleDisable}
/>
</>
);
};
export default App;
검색 (Search)
검색 상자가 있는 Transfer입니다.
import React, { useEffect, useState } from 'react';
import { Transfer } from 'antd';
import type { TransferProps } from 'antd';
interface RecordType {
key: string;
title: string;
description: string;
chosen: boolean;
}
const App: React.FC = () => {
const [mockData, setMockData] = useState<RecordType[]>([]);
const [targetKeys, setTargetKeys] = useState<TransferProps['targetKeys']>([]);
const getMock = () => {
const tempTargetKeys: React.Key[] = [];
const tempMockData: RecordType[] = [];
for (let i = 0; i < 20; 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 filterOption = (inputValue: string, option: RecordType) =>
option.description.includes(inputValue);
const handleChange: TransferProps['onChange'] = (newTargetKeys) => {
setTargetKeys(newTargetKeys);
};
const handleSearch: TransferProps['onSearch'] = (dir, value) => {
console.log('search:', dir, value);
};
return (
<Transfer
dataSource={mockData}
showSearch
filterOption={filterOption}
targetKeys={targetKeys}
onChange={handleChange}
onSearch={handleSearch}
render={(item) => item.title}
/>
);
};
export default App;
고급 (Advanced)
Transfer의 고급 사용법입니다.
전송 버튼의 라벨, 컬럼의 너비와 높이, 푸터에 표시할 내용을 커스터마이즈할 수 있습니다.
import React, { useEffect, useState } from 'react';
import { Button, Transfer } from 'antd';
import type { TransferProps } from 'antd';
interface RecordType {
key: string;
title: string;
description: string;
chosen: boolean;
}
const App: React.FC = () => {
const [mockData, setMockData] = useState<RecordType[]>([]);
const [targetKeys, setTargetKeys] = useState<TransferProps['targetKeys']>([]);
const getMock = () => {
const tempTargetKeys: React.Key[] = [];
const tempMockData: RecordType[] = [];
for (let i = 0; i < 20; 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: TransferProps['onChange'] = (newTargetKeys) => {
setTargetKeys(newTargetKeys);
};
const renderFooter: TransferProps['footer'] = (_, info) => {
if (info?.direction === 'left') {
return (
<Button
size="small"
style={{ display: 'flex', margin: 8, marginInlineEnd: 'auto' }}
onClick={getMock}
>
Left button reload
</Button>
);
}
return (
<Button
size="small"
style={{ display: 'flex', margin: 8, marginInlineStart: 'auto' }}
onClick={getMock}
>
Right button reload
</Button>
);
};
return (
<Transfer
dataSource={mockData}
showSearch
styles={{
section: {
width: 250,
height: 300,
},
}}
actions={['to right', 'to left']}
targetKeys={targetKeys}
onChange={handleChange}
render={(item) => `${item.title}-${item.description}`}
footer={renderFooter}
/>
);
};
export default App;
커스텀 데이터소스 (Custom datasource)
각 Transfer 항목을 커스터마이즈하여 복잡한 데이터소스를 렌더링할 수 있습니다.
import React, { useEffect, useState } from 'react';
import { Transfer } from 'antd';
import type { TransferProps } from 'antd';
interface RecordType {
key: string;
title: string;
description: string;
chosen: boolean;
}
const App: React.FC = () => {
const [mockData, setMockData] = useState<RecordType[]>([]);
const [targetKeys, setTargetKeys] = useState<React.Key[]>([]);
const getMock = () => {
const tempTargetKeys: React.Key[] = [];
const tempMockData: RecordType[] = [];
for (let i = 0; i < 20; 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: TransferProps['onChange'] = (newTargetKeys, direction, moveKeys) => {
console.log(newTargetKeys, direction, moveKeys);
setTargetKeys(newTargetKeys);
};
const renderItem = (item: RecordType) => {
const customLabel = (
<span className="custom-item">
{item.title} - {item.description}
</span>
);
return {
label: customLabel, // for displayed item
value: item.title, // for title and filter matching
};
};
return (
<Transfer
dataSource={mockData}
styles={{
section: {
width: 300,
height: 300,
},
}}
targetKeys={targetKeys}
onChange={handleChange}
render={renderItem}
/>
);
};
export default App;
커스텀 액션 (Custom Actions)
actions prop으로 작업을 커스터마이즈할 수 있습니다. 이 예제는 비활성화 및 로딩 상태 처리 등을 포함해 액션을 커스터마이즈하는 방법을 보여줍니다.
actions가 문자열 배열이면 기본 Button 컴포넌트가 사용되고 문자열이 버튼 텍스트로 설정됩니다.
actions가 React 요소 배열이면 이 요소들을 액션 버튼으로 직접 사용하여, 예제처럼 로딩 상태가 있는 버튼 같은 커스텀 버튼 컴포넌트를 사용할 수 있습니다.
참고:
- 커스텀 버튼을 사용할 때 Transfer 컴포넌트가 버튼의 비활성화 상태와 클릭 이벤트를 자동으로 처리합니다.
- 커스텀 버튼에
disabled속성을 추가해 비활성화 상태를 제어할 수 있습니다. - 커스텀 버튼에
onClick이벤트 핸들러를 추가할 수 있으며, Transfer 컴포넌트의 내부 핸들러와 병합됩니다.
import React, { useState } from 'react';
import { Button, message, Transfer } from 'antd';
import { DoubleLeftOutlined, DoubleRightOutlined } from '@ant-design/icons';
import type { TransferProps } from 'antd';
interface RecordType {
key: string;
title: string;
description: string;
}
const mockData: RecordType[] = Array.from({ length: 20 }).map((_, i) => ({
key: i.toString(),
title: `Content ${i + 1}`,
description: `Description ${i + 1}`,
}));
const initialTargetKeys = mockData.filter((item) => Number(item.key) > 10).map((item) => item.key);
const App: React.FC = () => {
const [messageApi, contextHolder] = message.useMessage();
const [targetKeys, setTargetKeys] = useState<string[]>(initialTargetKeys);
const [selectedKeys, setSelectedKeys] = useState<string[]>([]);
const [loadingRight, setLoadingRight] = useState<boolean>(false);
const [loadingLeft, setLoadingLeft] = useState<boolean>(false);
// Handle data transfer
const handleChange: TransferProps['onChange'] = (newTargetKeys, direction, moveKeys) => {
setTargetKeys(newTargetKeys as string[]);
// Simulate async action
if (direction === 'right') {
setLoadingRight(true);
setTimeout(() => {
setLoadingRight(false);
messageApi.success(`Successfully added ${moveKeys.length} items to the right`);
}, 1000);
} else {
setLoadingLeft(true);
setTimeout(() => {
setLoadingLeft(false);
messageApi.success(`Successfully added ${moveKeys.length} items to the left`);
}, 1000);
}
};
// Handle selection change
const handleSelectChange: TransferProps['onSelectChange'] = (
sourceSelectedKeys,
targetSelectedKeys,
) => {
setSelectedKeys([...sourceSelectedKeys, ...targetSelectedKeys] as string[]);
};
// Right button is disabled (no selected items on the left or all selected items are already in the right list)
const rightButtonDisabled =
selectedKeys.length === 0 || selectedKeys.every((key) => targetKeys.includes(key));
// Left button is disabled (no selected items on the right)
const leftButtonDisabled =
selectedKeys.length === 0 || selectedKeys.every((key) => !targetKeys.includes(key));
// Custom right button click handler
const handleRightButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
// You can add custom logic here, such as showing a confirmation dialog
console.log('Right button clicked', event);
// The Transfer component will automatically handle data transfer
};
// Custom left button click handler
const handleLeftButtonClick = (event: React.MouseEvent<HTMLButtonElement>) => {
// You can add custom logic here, such as showing a confirmation dialog
console.log('Left button clicked', event);
// The Transfer component will automatically handle data transfer
};
return (
<>
{contextHolder}
<Transfer
dataSource={mockData}
targetKeys={targetKeys}
selectedKeys={selectedKeys}
onChange={handleChange}
onSelectChange={handleSelectChange}
render={(item) => item.title}
actions={[
// Custom right button (transfer data to the right)
<Button
key="to-right"
type="primary"
icon={<DoubleRightOutlined />}
loading={loadingRight}
disabled={rightButtonDisabled}
onClick={handleRightButtonClick}
>
Move To Right
</Button>,
// Custom left button (transfer data to the left)
<Button
key="to-left"
type="primary"
icon={<DoubleLeftOutlined />}
loading={loadingLeft}
disabled={leftButtonDisabled}
onClick={handleLeftButtonClick}
>
Move To Left
</Button>,
]}
/>
</>
);
};
export default App;
페이징 (Pagination)
페이징으로 많은 양의 항목을 저장합니다.
import React, { useEffect, useState } from 'react';
import { Switch, Transfer } from 'antd';
import type { TransferProps } from 'antd';
interface RecordType {
key: string;
title: string;
description: string;
chosen: boolean;
}
const App: React.FC = () => {
const [oneWay, setOneWay] = useState(false);
const [mockData, setMockData] = useState<RecordType[]>([]);
const [targetKeys, setTargetKeys] = useState<React.Key[]>([]);
useEffect(() => {
const newTargetKeys: React.Key[] = [];
const newMockData: RecordType[] = [];
for (let i = 0; i < 2000; i++) {
const data = {
key: i.toString(),
title: `content${i + 1}`,
description: `description of content${i + 1}`,
chosen: i % 2 === 0,
};
if (data.chosen) {
newTargetKeys.push(data.key);
}
newMockData.push(data);
}
setTargetKeys(newTargetKeys);
setMockData(newMockData);
}, []);
const onChange: TransferProps['onChange'] = (newTargetKeys, direction, moveKeys) => {
console.log(newTargetKeys, direction, moveKeys);
setTargetKeys(newTargetKeys);
};
return (
<>
<Transfer
dataSource={mockData}
targetKeys={targetKeys}
onChange={onChange}
render={(item) => item.title}
oneWay={oneWay}
pagination
/>
<br />
<Switch
unCheckedChildren="one way"
checkedChildren="one way"
checked={oneWay}
onChange={setOneWay}
/>
</>
);
};
export default App;
테이블 전송 (Table Transfer)
Table 컴포넌트로 렌더 리스트를 커스터마이즈합니다.
import React, { useState } from 'react';
import { Flex, Switch, Table, Tag, Transfer } from 'antd';
import type { GetProp, TableColumnsType, TableProps, TransferProps } from 'antd';
type TransferItem = GetProp<TransferProps, 'dataSource'>[number];
type TableRowSelection<T extends object> = TableProps<T>['rowSelection'];
interface DataType {
key: string;
title: string;
description: string;
tag: string;
disabled?: boolean;
}
interface TableTransferProps extends TransferProps<TransferItem> {
dataSource: DataType[];
leftColumns: TableColumnsType<DataType>;
rightColumns: TableColumnsType<DataType>;
}
// Customize Table Transfer
const TableTransfer: React.FC<TableTransferProps> = (props) => {
const { leftColumns, rightColumns, ...restProps } = props;
return (
<Transfer style={{ width: '100%' }} {...restProps}>
{({
direction,
filteredItems,
onItemSelect,
onItemSelectAll,
selectedKeys: listSelectedKeys,
disabled: listDisabled,
}) => {
const columns = direction === 'left' ? leftColumns : rightColumns;
const rowSelection: TableRowSelection<TransferItem> = {
getCheckboxProps: () => ({ disabled: listDisabled }),
onChange(selectedRowKeys) {
onItemSelectAll(selectedRowKeys, 'replace');
},
selectedRowKeys: listSelectedKeys,
selections: [Table.SELECTION_ALL, Table.SELECTION_INVERT, Table.SELECTION_NONE],
};
return (
<Table<DataType>
rowSelection={rowSelection}
columns={columns}
dataSource={filteredItems}
size="small"
style={{ pointerEvents: listDisabled ? 'none' : undefined }}
onRow={({ key, disabled: itemDisabled }) => ({
onClick: () => {
if (itemDisabled || listDisabled) {
return;
}
onItemSelect(key, !listSelectedKeys.includes(key));
},
})}
/>
);
}}
</Transfer>
);
};
const mockTags = ['cat', 'dog', 'bird'];
const mockData = Array.from({ length: 20 }).map<DataType>((_, i) => ({
key: i.toString(),
title: `content${i + 1}`,
description: `description of content${i + 1}`,
tag: mockTags[i % 3],
}));
const columns: TableColumnsType<DataType> = [
{
dataIndex: 'title',
title: 'Name',
},
{
dataIndex: 'tag',
title: 'Tag',
render: (tag: string) => (
<Tag style={{ marginInlineEnd: 0 }} color="cyan">
{tag.toUpperCase()}
</Tag>
),
},
{
dataIndex: 'description',
title: 'Description',
},
];
const filterOption = (input: string, item: DataType) =>
item.title?.includes(input) || item.tag?.includes(input);
const App: React.FC = () => {
const [targetKeys, setTargetKeys] = useState<TransferProps['targetKeys']>([]);
const [disabled, setDisabled] = useState(false);
const onChange: TableTransferProps['onChange'] = (nextTargetKeys) => {
setTargetKeys(nextTargetKeys);
};
const toggleDisabled = (checked: boolean) => {
setDisabled(checked);
};
return (
<Flex align="start" gap="medium" vertical>
<TableTransfer
dataSource={mockData}
targetKeys={targetKeys}
disabled={disabled}
showSearch
showSelectAll={false}
onChange={onChange}
filterOption={filterOption}
leftColumns={columns}
rightColumns={columns}
/>
<Switch
unCheckedChildren="disabled"
checkedChildren="disabled"
checked={disabled}
onChange={toggleDisabled}
/>
</Flex>
);
};
export default App;
트리 전송 (Tree Transfer)
Tree 컴포넌트로 렌더 리스트를 커스터마이즈합니다.
import React, { useState } from 'react';
import { theme, Transfer, Tree } from 'antd';
import type { GetProp, TransferProps, TreeDataNode } from 'antd';
type TransferItem = GetProp<TransferProps, 'dataSource'>[number];
interface TreeTransferProps {
dataSource: TreeDataNode[];
targetKeys: TransferProps['targetKeys'];
onChange: TransferProps['onChange'];
}
// Customize Table Transfer
const isChecked = (selectedKeys: React.Key[], eventKey: React.Key) =>
selectedKeys.includes(eventKey);
const generateTree = (
treeNodes: TreeDataNode[] = [],
checkedKeys: TreeTransferProps['targetKeys'] = [],
): TreeDataNode[] =>
treeNodes.map(({ children, ...props }) => ({
...props,
disabled: checkedKeys.includes(props.key as string),
children: generateTree(children, checkedKeys),
}));
const TreeTransfer: React.FC<TreeTransferProps> = (props) => {
const { token } = theme.useToken();
const { dataSource, targetKeys = [], ...restProps } = props;
const transferDataSource: TransferItem[] = [];
function flatten(list: TreeDataNode[] = []) {
list.forEach((item) => {
transferDataSource.push(item as TransferItem);
flatten(item.children);
});
}
flatten(dataSource);
return (
<Transfer
{...restProps}
targetKeys={targetKeys}
dataSource={transferDataSource}
render={(item) => item.title}
showSelectAll={false}
>
{({ direction, onItemSelect, selectedKeys }) => {
if (direction === 'left') {
const checkedKeys = [...selectedKeys, ...targetKeys];
return (
<div style={{ padding: token.paddingXS }}>
<Tree
blockNode
checkable
checkStrictly
defaultExpandAll
checkedKeys={checkedKeys}
treeData={generateTree(dataSource, targetKeys)}
onCheck={(_, { node: { key } }) => {
onItemSelect(key as string, !isChecked(checkedKeys, key));
}}
onSelect={(_, { node: { key } }) => {
onItemSelect(key as string, !isChecked(checkedKeys, key));
}}
/>
</div>
);
}
}}
</Transfer>
);
};
const treeData: TreeDataNode[] = [
{ key: '0-0', title: '0-0' },
{
key: '0-1',
title: '0-1',
children: [
{ key: '0-1-0', title: '0-1-0' },
{ key: '0-1-1', title: '0-1-1' },
],
},
{ key: '0-2', title: '0-2' },
{ key: '0-3', title: '0-3' },
{ key: '0-4', title: '0-4' },
];
const App: React.FC = () => {
const [targetKeys, setTargetKeys] = useState<TreeTransferProps['targetKeys']>([]);
const onChange: TreeTransferProps['onChange'] = (keys) => {
setTargetKeys(keys);
};
return <TreeTransfer dataSource={treeData} targetKeys={targetKeys} onChange={onChange} />;
};
export default App;
상태 (Status)
status로 Transfer에 상태를 추가합니다. error 또는 warning이 될 수 있습니다.
import React from 'react';
import { Flex, Transfer } from 'antd';
const App: React.FC = () => (
<Flex gap="medium" vertical>
<Transfer status="error" />
<Transfer status="warning" showSearch />
</Flex>
);
export default App;
커스텀 시맨틱 DOM 스타일링 (Custom semantic dom styling)
classNames와 styles에 객체 또는 함수를 넘겨서 Transfer의 시맨틱 DOM 스타일을 커스터마이즈할 수 있습니다.
import React from 'react';
import { Flex, Transfer } from 'antd';
import type { GetProp, TransferProps } from 'antd';
import { createStyles } from 'antd-style';
const useStyles = createStyles(({ token, css }) => ({
section: { backgroundColor: 'rgba(250,250,250, 0.5)' },
header: { color: token.colorPrimary },
actions: css`
& button {
background-color: rgba(255, 242, 232, 0.6);
}
`,
}));
const mockData = Array.from({ length: 20 }).map<any>((_, i) => ({
key: i.toString(),
title: `content${i + 1}`,
description: `description of content${i + 1}`,
}));
const initialTargetKeys = mockData.filter((item) => Number(item.key) > 10).map((item) => item.key);
const stylesObject: TransferProps['styles'] = {
header: { fontWeight: 'bold' },
};
const stylesFn: TransferProps['styles'] = (info): GetProp<TransferProps, 'styles', 'Return'> => {
if (info.props.status === 'warning') {
return {
section: { backgroundColor: 'rgba(246,255,237, 0.6)', borderColor: '#b7eb8f' },
header: { color: '#8DBCC7', fontWeight: 'normal' },
};
}
return {};
};
const App: React.FC = () => {
const { styles: classNames } = useStyles();
const sharedProps: TransferProps = {
dataSource: mockData,
targetKeys: initialTargetKeys,
render: (item) => item.title,
classNames,
};
return (
<Flex vertical gap="large" style={{ width: '100%' }}>
<Transfer {...sharedProps} status="error" styles={stylesObject} />
<Transfer {...sharedProps} status="warning" styles={stylesFn} />
</Flex>
);
};
export default App;
API
Common props ref:Common props
Transfer
| Property | Description | Type | Default | Version | Global Config |
|---|---|---|---|---|---|
| actions | A set of operations that are sorted from top to bottom. When an array of strings is provided, default buttons will be used; when an array of ReactNode is provided, custom elements will be used | ReactNode[] | [>, <] |
6.0.0 | × |
| classNames | Customize class for each semantic structure inside the component. Supports object or function. | Record<SemanticDOM, string> | (info: { props })=> Record<SemanticDOM, string> | - | 6.0.0 | 6.0.0 |
| dataSource | Used for setting the source data. The elements that are part of this array will be present the left column. Except the elements whose keys are included in targetKeys prop |
RecordType extends TransferItem = TransferItem[] | [] | × | |
| disabled | Whether disabled transfer | boolean | false | × | |
| selectionsIcon | custom dropdown icon | React.ReactNode | 5.8.0 | 5.14.0 | |
| filterOption | A function to determine whether an item should show in search result list, only works when searching, (add direction support since 5.9.0+) |
(inputValue, option, direction: left | right): boolean |
- | × | |
| footer | A function used for rendering the footer | (props, { direction }) => ReactNode | - | direction: 4.17.0 | × |
A custom CSS style used for rendering the transfer columns. Use styles.section instead |
object | ({direction: left | right}) => object |
- | × | ||
| locale | The i18n text including filter, empty text, item unit, etc | { itemUnit: string; itemsUnit: string; searchPlaceholder: string; notFoundContent: ReactNode | ReactNode[]; } | { itemUnit: item, itemsUnit: items, notFoundContent: No data, searchPlaceholder: Search here } |
× | |
| oneWay | Display as single direction style | boolean | false | 4.3.0 | × |
A set of operations that are sorted from top to bottom. Use actions instead. |
string[] | [>, <] |
× | ||
A custom CSS style used for rendering the operations column. Use styles.actions instead. |
object | - | × | ||
| pagination | Use pagination. Not work in render props | boolean | { pageSize: number, simple: boolean, showSizeChanger?: boolean, showLessItems?: boolean } | false | 4.3.0 | × |
| render | The function to generate the item shown on a column. Based on an record (element of the dataSource array), this function should return a React element which is generated from that record. Also, it can return a plain object with value and label, label is a React element and value is for title |
(record) => ReactNode | - | × | |
| selectAllLabels | A set of customized labels for select all checkboxes on the header | (ReactNode | (info: { selectedCount: number, totalCount: number }) => ReactNode)[] | - | × | |
| selectedKeys | A set of keys of selected items | string[] | number[] | [] | × | |
| showSearch | If included, a search box is shown on each column | boolean | { placeholder:string,defaultValue:string } | false | × | |
| showSelectAll | Show select all checkbox on the header | boolean | true | × | |
| status | Set validation status | 'error' | 'warning' | - | 4.19.0 | × |
| styles | Customize inline style for each semantic structure inside the component. Supports object or function. | Record<SemanticDOM, CSSProperties> | (info: { props })=> Record<SemanticDOM, CSSProperties> | - | 6.0.0 | 6.0.0 |
| targetKeys | A set of keys of elements that are listed on the right column | string[] | number[] | [] | × | |
| titles | A set of titles that are sorted from left to right | ReactNode[] | - | × | |
| onChange | A callback function that is executed when the transfer between columns is complete | (targetKeys, direction, moveKeys): void | - | × | |
| onScroll | A callback function which is executed when scroll options list | (direction, event): void | - | × | |
| onSearch | A callback function which is executed when search field are changed | (direction: left | right, value: string): void |
- | × | |
| onSelectChange | A callback function which is executed when selected items are changed | (sourceSelectedKeys, targetSelectedKeys): void | - | × |
렌더 props (Render Props)
Transfer는 children을 받아 렌더 리스트를 커스터마이즈하며, 다음 props를 사용합니다:
| Property | Description | Type | Version |
|---|---|---|---|
| direction | List render direction | left | right |
|
| disabled | Disable list or not | boolean | |
| filteredItems | Filtered items | RecordType[] | |
| selectedKeys | Selected items | string[] | number[] | |
| onItemSelect | Select item | (key: string | number, selected: boolean) | |
| onItemSelectAll | Select a group of items | (keys: string[] | number[], selected: boolean) |
예제 (example)
<Transfer {...props}>{(listProps) => <YourComponent {...listProps} />}</Transfer>
경고 (Warning)
React의 표준에 따라 key는 항상 배열의 요소에 직접 제공되어야 합니다. Transfer에서는 dataSource 배열에 포함된 요소에 key가 설정되어야 합니다. 기본적으로 key 속성이 고유 식별자로 사용됩니다.
데이터에 key가 없다면 rowKey를 사용해 각 요소를 고유하게 식별하는 key를 지정해야 합니다.
// eg. your primary key is `uid`
return <Transfer rowKey={(record) => record.uid} />;
시맨틱 DOM (Semantic DOM)
https://ant.design/components/transfer/semantic.md
디자인 토큰 (Design Token)
컴포넌트 토큰 (Component Token - Transfer)
| Token Name | Description | Type | Default Value |
|---|---|---|---|
| headerHeight | Height of header | string | number | 40 |
| itemHeight | Height of list item | string | number | 32 |
| itemPaddingBlock | Vertical padding of list item | string | number | 5 |
| listHeight | Height of list | string | number | 200 |
| listWidth | Width of list | string | number | 180 |
| listWidthLG | Width of large list | string | number | 250 |
글로벌 토큰 (Global Token)
| Token Name | Description | Type | Default Value |
|---|---|---|---|
| borderRadiusLG | LG size border radius, used in some large border radius components, such as Card, Modal and other components. | number | |
| colorBgContainer | Container background color, e.g: default button, input box, etc. Be sure not to confuse this with colorBgElevated. |
string | |
| colorBgContainerDisabled | Control the background color of container in disabled state. | string | |
| colorBorder | Default border color, used to separate different elements, such as: form separator, card separator, etc. | string | |
| colorError | Used to represent the visual elements of the operation failure, such as the error Button, error Result component, etc. | string | |
| colorLink | Control the color of hyperlink. | string | |
| colorLinkActive | Control the color of hyperlink when clicked. | string | |
| colorLinkHover | Control the color of hyperlink when hovering. | string | |
| colorPrimaryBorder | The stroke color under the main color gradient, used on the stroke of components such as Slider. | string | |
| colorSplit | Used as the color of separator, this color is the same as colorBorderSecondary but with transparency. | string | |
| colorText | Default text color which comply with W3C standards, and this color is also the darkest neutral color. | string | |
| colorTextDisabled | Control the color of text in disabled state. | string | |
| colorTextSecondary | The second level of text color is generally used in scenarios where text color is not emphasized, such as label text, menu text selection state, etc. | string | |
| colorWarning | Used to represent the warning map token, such as Notification, Alert, etc. Alert or Control component(like Input) will use these map tokens. | string | |
| controlHeightLG | LG component height | number | |
| controlItemBgActive | Control the background color of control component item when active. | string | |
| controlItemBgActiveHover | Control the background color of control component item when hovering and active. | string | |
| controlItemBgHover | Control the background color of control component item when hovering. | string | |
| fontFamily | The font family of Ant Design prioritizes the default interface font of the system, and provides a set of alternative font libraries that are suitable for screen display to maintain the readability and readability of the font under different platforms and browsers, reflecting the friendly, stable and professional characteristics. | string | |
| fontSize | The most widely used font size in the design system, from which the text gradient will be derived. | number | |
| fontSizeIcon | Control the font size of operation icon in Select, Cascader, etc. Normally same as fontSizeSM. | number | |
| lineHeight | Line height of text. | number | |
| lineType | Border style of base components | string | |
| lineWidth | Border width of base components | number | |
| lineWidthFocus | Control the width of the line when the component is in focus state. | number | |
| linkDecoration | Control the text decoration style of a link. | TextDecoration<string | number> | undefined | |
| linkFocusDecoration | Control the text decoration style of a link on focus. | TextDecoration<string | number> | undefined | |
| linkHoverDecoration | Control the text decoration style of a link on mouse hover. | TextDecoration<string | number> | undefined | |
| marginXS | Control the margin of an element, with a small size. | number | |
| marginXXS | Control the margin of an element, with the smallest size. | number | |
| motionDurationSlow | Motion speed, slow speed. Used for large element animation interaction. | string | |
| paddingSM | Control the small padding of the element. | number | |
| paddingXS | Control the extra small padding of the element. | number |
FAQ
Transfer 컬럼에서 원격 서버의 데이터를 가져와 표시하는 방법이 궁금합니다. {#faq-async-data-loading}
페이지 번호를 동기화하려면 옵션을 제거하지 않고 체크한 컬럼을 비활성화하면 됩니다: https://codesandbox.io/s/objective-wing-6iqbx