ant.design

kirin.logยท2021๋…„ 9์›” 2์ผ
0
post-custom-banner

๐Ÿง Ant.design (antd)

  • UI๋ฅผ ์œ„ํ•œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์ด๋‹ค.
  • React, Angular, Vue ๋“ฑ์„ ์œ„ํ•œ ์ปดํฌ๋„ŒํŠธ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฒ„์ „๋„ ์กด์žฌํ•œ๋‹ค.
  • ์ตœ์‹  ๋ธŒ๋ผ์šฐ์ € ๋ฐ Internet Explorer 11๋ฅผ ์ง€์›ํ•œ๋‹ค.

๐Ÿณ React + Typescript + Antd

React + Typescript ํ™˜๊ฒฝ์—์„œ ๊ฐœ๋ฐœ

๐Ÿ“Œ ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋Š” antd์— ๋‚ด์žฅ๋˜์–ด ์žˆ์œผ๋ฏ€๋กœ (ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ๋ฅผ) ๋”ฐ๋กœ ์„ค์น˜ํ•˜์ง€ ์•Š๋Š”๋‹ค โžก๏ธ @types/antd

์„ค์น˜

$ npm install antd
$ yarn add antd

์‚ฌ์šฉ

// src/App.tsx
import React, { FC } from 'react';
import { Button } from 'antd';  // Button ์ปดํฌ๋„ŒํŠธ import
import './App.css';

const App = () => (
  <div className="App">
    <Button type="primary">Button</Button> // ์ปดํฌ๋„ŒํŠธ ํ™œ์šฉ
  </div>
);

export default App;

โ—๏ธ src/App.css ์— ์•„๋ž˜ ์ถ”๊ฐ€ํ•˜๊ธฐ
@import '~antd/dist/antd.css';
๋˜๋Š” styledComponent ๋กœ ์ž‘์—… ๊ฐ€๋Šฅํ•˜๋‹ค

๐Ÿ”จ styledComponent ์ ์šฉ ์˜ˆ์‹œ

import * as React from 'react';
import { styled } from 'styledComponents';

// styledComponents ์ ์šฉ(Component ์ƒ์„ฑ)
const Component = styled.div`
  width: 100%;
  font-size: 0.8em;
  color: ${p => p.theme.normal_color};

  [data-container] {
    height: 60px;
    justify-content: center;
  }
`;

// IProps ์ธํ„ฐํŽ˜์ด์Šค ์ƒ์„ฑ(ํƒ€์ž… ์ง€์ • - string)
interface IProps {
  className?: string;
}

class Footer extends React.Component<IProps> {
  render() {
    return (
      <Component> // styledComponent๋กœ ์Šคํƒ€์ผ๋ง ํ•œ ํƒœ๊ทธ
        <div data-container>
          Co-working space, Floor 3rd, Hanoi
          8:00 - 11:00 Sunday, Oct 14th, 2018
        </div>
      </Component>
    );
  }
}

antd๋กœ ๋‹ค์–‘ํ•œ UI Component๋ฅผ ํ™œ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ, ๋Œ€ํ‘œ์ ์œผ๋กœ ์‚ฌ์šฉ๋˜๋Š” table์„ ํ™œ์šฉํ•˜๋Š” ์˜ˆ์‹œ๋ฅผ ์„ค๋ช…ํ•ด๋ณด์ž.

๐Ÿ“Œ coloum๊ณผ data๋ฅผ jsonํ˜•ํƒœ๋กœ ์ง€์ • ํ›„, antd ์ปดํฌ๋„ŒํŠธ์— ์†์„ฑ์œผ๋กœ ๋„ฃ์–ด์ฃผ๋Š” ๋ฐฉ์‹์ด๋‹ค.

import { Table } from 'antd'; // table ๋ถˆ๋Ÿฌ์˜ค๊ธฐ

  // columns ์ง€์ • (์ด 3๊ฐœ์˜ columns์ด ์ƒ๊ธด๋‹ค)
const columns = [
  {
    title: 'Name',     // title: ์ œ๋ชฉ๋ผ์ธ
    dataIndex: 'name', // dataIndex: ์‹ค์ œ ๊ฐ’
    key: 'name',       // dataIndex์™€ ์ผ์น˜ํ•ด์•ผ ํ•˜๋ฉฐ, dataIndex๊ฐ€ ์žˆ์œผ๋ฉด ๊ตณ์ด ํ•„์š”์—†์Œ
    width: 150,
    render: text => <a>{text}</a>,
  },
  {
    title: 'Age',
    dataIndex: 'age',
    key: 'age',
    width: 80,
  },
  {
    title: 'Address',
    dataIndex: 'address',
    key: 'address 1',
    ellipsis: true,
  },
];

  // data ์ง€์ • (columns์˜ dataIndex์™€ ์ผ์น˜ํ•ด์•ผ ํ•œ๋‹ค)
const data = [
  {
    key: '1',
    name: 'John Brown',  
    age: 32,
    address: 'New York No. 1 Lake Park, New York No. 1 Lake Park',
  },
  {
    key: '2',
    name: 'Jim Green',
    age: 42,
    address: 'London No. 2 Lake Park, London No. 2 Lake Park',
  },
];

ReactDOM.render(
  <Table columns={columns} dataSource={data} />
);

๐ŸŒˆ antd API

๊ณต์‹ ๋ฌธ์„œ ์ฐธ๊ณ 

antd API๋ฅผ ํ™œ์šฉํ•ด์„œ ๋‹ค์–‘ํ•œ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•์ด ๊ฐ€๋Šฅํ•˜๋‹ค.
Table ๋ฐ Column ์˜ ๋Œ€ํ‘œ์ ์ธ API์™€ ์ด๋ฅผ ํ™œ์šฉํ•œ ์˜ˆ์‹œ๋ฅผ ๋“ค์–ด๋ณด์ž!

// MARK: ์ปฌ๋Ÿผ ์…‹ํŒ….
const TableColumns:Array<String> = [
    {
      title: 'EMAIL',   // ์ œ๋ชฉ ํ–‰์— ๋“ค์–ด๊ฐ€๋Š” ์ด๋ฆ„
      key: 'email',
      dataIndex: 'email',  // ์‹ค์ œ data
      width: '30px',
      align: 'center',
    },
    {
      title: 'NAME',
      key: 'name', 
      dataIndex: 'name',
      align: 'center',
      width: '60px',
      fixed: true,
    },
    {
      title: t('page.host_list.table.header.created'),
      key: 'createdAt',
      dataIndex: 'createdAt',   // ํ˜„์žฌ ๋‚ ์งœ์ •๋ณด๋ฅผ ํ‘œ๊ธฐํ•˜๋Š” ์†์„ฑ 
      width: '140px',
      align: 'center',
      // ํŠน์ • ํ‚ค:๊ฐ’์„ returnํ•˜๋„๋ก "render ์†์„ฑ"์„ ์ ์šฉํ•œ๋‹ค.
      render: (value) => dateFormat(new Date(value), 'simple', language),
    },
    {
      title: 'OPTION',
      key: 'option',
      width: '80px',
      align: 'center',
      // ํŠน์ • ํƒœ๊ทธ๋ฅผ returnํ•˜๋„๋ก "render ์†์„ฑ"์„ ์ ์šฉํ•œ๋‹ค.
      render: (_, record) => {        
        return (
          <>
            <Popconfirm 
              title="๋น„๋ฐ€๋ฒˆํ˜ธ๋ฅผ ๋ฆฌ์…‹ํ•˜์‹œ๊ฒ ์Šต๋‹ˆ๊นŒ?" 
              onConfirm={() => {
                passwordReset(record)
              }
            }>
              <ResetBtn>๋ฆฌ์…‹</ResetBtn>
            </Popconfirm>
        )
      },
    }]  

โญ๏ธ render ์†์„ฑ์€ 2๊ฐœ์˜ ์ธ์ž๋ฅผ ๋ฐ›๋Š”๋‹ค. (value, record)
value ์ธ์ž๋ฅผ ๋ฐ›์„ ํ•„์š”๊ฐ€ ์—†์œผ๋ฉด ์ž„์˜๋กœ '_'๋ฅผ ๋„ฃ์–ด์ค„ ์ˆ˜ ์žˆ๋‹ค. ('_', render)
record ์ธ์ž๋ฅผ ๋ฐ›์„ ํ•„์š”๊ฐ€ ์—†์œผ๋ฉด ๊ทธ๋ƒฅ ์ฒซ๋ฒˆ์งธ ์ธ์ž์ธ value๋งŒ ํ‘œ๊ธฐํ•ด๋„ ๋จ.

์ฒซ ๋ฒˆ์งธ ์ธ์ž์ธ value์—์„œ๋Š” ๊ฐ์ฒด ์•ˆ์˜ ํŠน์ • ํ‚ค:๊ฐ’์„ ๋ฐ›๋Š”๋‹ค.
์˜ˆ) ์œ„ ์˜ˆ์‹œ์—์„œ
[
{title:-- , key:--, dataIndex:-- },
{title:-- , key:--, dataIndex:--},
{title:-- , key:--, dataIndex:--}
]
๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค.
value์ธ์ž๋Š” ํ•ด๋‹น ๊ฐ์ฒด ์•ˆ์˜ title ๋˜๋Š” key ๋˜๋Š” dataIndex ์˜ ํŠน์ • ํ‚ค:๊ฐ’์„ ์˜๋ฏธํ•  ์ˆ˜ ์žˆ๋‹ค.

๋”ฐ๋ผ์„œ ์œ„์˜ value ํ‚ค:๊ฐ’์€ dataIndex: createdAt์„ ์˜๋ฏธํ•˜๋ฉฐ, ํ•ด๋‹น value์ •๋ณด๋กœ render์— ๋ณ€ํ˜•๊ฐ’์„ ์ถœ๋ ฅํ•œ๋‹ค.

๋‘ ๋ฒˆ์งธ ์ธ์ž์ธ record์—์„œ๋Š” ๋ฐฐ์—ด ์•ˆ์˜ ํŠน์ • ๊ฐ์ฒด({--})๋ฅผ ๋ฐ›๋Š”๋‹ค.
์˜ˆ) ์œ„ ์˜ˆ์‹œ์—์„œ render์ธ์ž๋Š” ํ•ด๋‹น ๊ฐ์ฒด ์•ˆ์˜ {--} ๋ฌถ์Œ์ด ๋  ์ˆ˜ ์žˆ๋‹ค. {title:-- , key:--, dataIndex:-- }

๋”ฐ๋ผ์„œ ์œ„์˜ record ๊ฐ’์€ ํ•ด๋‹น ๊ฐ์ฒด ์•ˆ์˜ ๋ชจ๋“  ํ‚ค:๊ฐ’์„ ์ ์šฉํ•˜๋ฏ€๋กœ, return ์œผ๋กœ ์ถœ๋ ฅ๋˜๋Š” ๋‚ด์šฉ์— ๋ชจ๋“  ํ‚ค:๊ฐ’์„ ํฌํ•จํ•œ๋‹ค.

profile
boma91@gmail.com
post-custom-banner

0๊ฐœ์˜ ๋Œ“๊ธ€