Style

Ant-design / Styled-components

์„ค์น˜

๋จผ์ € ํŒจํ‚ค์ง€๋ฅผ ์„ค์น˜ํ•ด ์ค๋‹ˆ๋‹ค.

@ant-design/icons ๋ฅผ ๋”ฐ๋กœ ์„ค์น˜ํ•ด์ค˜์•ผ ํ•˜๋Š” ์ด์œ ๋Š” ๋ณดํ†ต icon๊ณผ ๊ฐ™์€ ์ด๋ฏธ์ง€ ํŒจํ‚ค์ง€์˜ ํฌ๊ธฐ๊ฐ€ ํฌ๊ธฐ ๋•Œ๋ฌธ์ž…๋‹ˆ๋‹ค.

yarn add antd styled-component @ant-design/icons
  "dependencies": {
    "@ant-design/icons": "^4.2.1",
    "antd": "^4.5.1",
    "next": "^9.5.0",
    "react": "^16.13.1",
    "react-dom": "^16.13.1",
    "styled-components": "^5.1.1"
  },

Ant-design์ด๋‚˜ Bootstrap์€ ๋ณดํ†ต ์‹ค๋ฌด์—์„œ๋Š” ๊ด€๋ฆฌ์žํŽ˜์ด์ง€์™€ ๊ฐ™์ด ๋””์ž์ธ์˜ ์ค‘์š”์„ฑ์ด ์กฐ๊ธˆ์€ ๋–จ์–ด์ง€๋Š” ํŽ˜์ด์ง€์— ์‚ฌ์šฉ๋ฉ๋‹ˆ๋‹ค.

์œ„ ํŽ˜์ด์ง€์—์„œ ์ปดํฌ๋„ŒํŠธ ๋ชฉ๋ก์„ ํ™•์ธํ• ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ ์šฉ์‹œํ‚ค๊ธฐ

Menu component๋ฅผ ๊ฐ€์ ธ์˜ค๊ฒŒ ๋œ๋‹ค๋ฉด

AppLayout.js
import React from "react";
import Link from "next/Link"; //importํ•ด์ฃผ๊ธฐ
import { Menu } from "antd";

export default function AppLayout({ children }) {
  return (
  <>
    <Menu mode="horizontal">
      <Menu.Item>
        <Link href="/">
          <a>Conrad</a>
        </Link>
      </Menu.Item>
      <Menu.Item>
        <Link href="/profile">
          {/* Linkํƒœ๊ทธ ์•ˆ์—์„œ href ํ•ด์ค€๋’ค ๋‚ด๋ถ€์— aํƒœ๊ทธ */}
          <a>ํ”„๋กœํ•„</a>
        </Link>
      </Menu.Item>
      <Menu.Item>
        <Link href="/signup">
          <a>ํšŒ์›๊ฐ€์ž…</a>
        </Link>
      </Menu.Item>
      
    </Menu>
{children}
</>
  );
}

์ด๋ ‡๊ฒŒ ์ž‘์—…ํ•˜๋ฉด ๋˜์ง€๋งŒ

CSS๊ฐ€ ๊นจ์ง‘๋‹ˆ๋‹ค.

next๋Š” ์•ˆ์— webPack์ด ๋‚ด์žฅ๋˜์–ด์žˆ๋Š”๋ฐ, css๋ฅผ ๋ณด๋Š”์ˆœ๊ฐ„ js์— ๋„ฃ์–ด์ฃผ๊ฒŒ๋ฉ๋‹ˆ๋‹ค..

pages์˜ ๊ณตํ†ต์œผ๋กœ ์ ์šฉํ•  ๊ฒƒ์ด์ด ์žˆ์„๋•Œ๋Š”, ๋ชจ๋“  page์—์„œ ์ผ์ผ์ด ์จ์ฃผ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๋ผ

pagesํด๋” ์•ˆ์— _app.js๋ฅผ ๋งŒ๋“ค์–ด ๊ณตํ†ต์ ์ธ ์š”์†Œ๋ฅผ ํ•˜๋‚˜๋กœ ์ฒ˜๋ฆฌํ•ด์ฃผ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

import React from "react";
import "antd/dist/antd.css";

export default function App({ Component }) {
  return <Component />;
}

์ด๋ ‡๊ฒŒ ๋˜๋ฉด _app.js๋Š” ๋‹ค๋ฅธ ํŽ˜์ด์ง€๋“ค์˜ ๋ถ€๋ชจ์š”์†Œ๊ฐ€ ๋ฉ๋‹ˆ๋‹ค. (HOC๊ฐ€ ๋˜๋Š”๊ฒƒ์ด์ฃ )

Component๋Š” ๋‹ค๋ฅธ ์š”์†Œ๋“ค ์ฆ‰ ์ถœ๋ ฅํ•  ํŽ˜์ด์ง€๋ฅผ ์˜๋ฏธํ•˜๊ฒŒ ๋ฉ๋‹ˆ๋‹ค.

์ด๋ฟ์•„๋‹ˆ๋ผ ๋ชจ๋“ ํŽ˜์ด์ง€์— ๊ณตํ†ต๋˜๋Š” ๊ฒƒ๋“ค์„ ์ ์–ด์ฃผ๋ฉด ๋œ๋‹ต๋‹ˆ๋‹ค.

_app.js : ๋ชจ๋“  ํŽ˜์ด์ง€์˜ ๊ณตํ†ต๋˜๋Š” ๊ฒƒ๋“ค

Layout : ์ผ๋ถ€ ํŽ˜์ด์ง€์— ๊ณตํ†ต์ธ ๊ฒƒ๋“ค

next๋Š” HTML์˜ headํƒœ๊ทธ๋ฅผ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

๋˜ํ•œ ์•„๋ž˜์™€ ๊ฐ™์ด HTML์˜ title์ด๋‚˜ meta๋„ ์ง€์ •ํ•ด ์ค„ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import React from "react";
import Head from "next/head";
import "antd/dist/antd.css";

export default function _app({ Component }) {
  return (
    <div>
      <Head>
        <meta charSet="utf-8"></meta>
        <title>Wongeun</title>
      </Head>
      <Component />
    </div>
  );
}

๋งŒ์•ฝ ๊ณตํ†ต๋˜์ง€ ์•Š๋Š” Head๋ผ๋ฉด index.js์— ๋„ฃ์–ด์ฃผ์‹œ๋ฉด ๋ฉ๋‹ˆ๋‹ค.

CSS์ˆ˜์ •ํ•˜๊ธฐ

์•„๋ž˜์™€ ๊ฐ™์ด ๊ฒ€์ƒ‰์ฐฝ์„ ๋„ฃ์–ด์ฃผ์„ธ์—ฌ

<>
      <Menu mode="horizontal">
        <Menu.Item>
          <Link href="/">
            <a>Home</a>
          </Link>
        </Menu.Item>
        <Menu.Item>
          <Link href="/profile">
            <a>ํ”„๋กœํ•„</a>
          </Link>
        </Menu.Item>
        <Menu.Item>
          <Link href="/signup">
            <a>ํšŒ์›๊ฐ€์ž…</a>
          </Link>
        </Menu.Item>
        // ๊ฒ€์ƒ‰์ถ”๊ฐ€
        <Menu.Item>
          <Input.Search enterButton></Input.Search>
        </Menu.Item>
      </Menu>
      {children}
    </>
์œ„์น˜๊ฐ€ ๋ญ”๊ฐ€ ์ด์ƒํ•˜์ฃ ?
<Input.Search
            enterButton
            style={{ verticalAlign: "middle" }}
          ></Input.Search>

์ด๋ ‡๊ฒŒ css๋ฅผ ์ค„ ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

๋ฐ˜์‘ํ˜•

์ด๋Ÿฐ CSS์‹œ์Šคํ…œ์€ Grid ์‹œ์Šคํ…œ์„ ๊ฐ€์ง€๊ณ  ์žˆ๋Š”๋ฐ

๋ชจ๋ฐ”์ผํŽ˜์ด์ง€๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ•์—๋Š” ๋‘๊ฐ€์ง€๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. ๋ฐ˜์‘ํ˜• - ํ™”๋ฉดํฌ๊ธฐ์— ๋”ฐ๋ผ ์ปดํฌ๋„ŒํŠธ๋“ค์ด ์žฌ๋ฐฐ์น˜ ๋˜๋Š” ๊ฒƒ.

  2. ์ ์‘ํ˜• - ๋ชจ๋ฐ”์ผํŽ˜์ด์ง€ ๋”ฐ๋กœ, ๋ฐ์Šคํฌํƒ‘ ํŽ˜์ด์ง€ ๋”ฐ๋กœ ๋งŒ๋“œ๋Š” ๊ฒƒ.

Ant-Design์—์„œ๋Š” ๋ฐ˜์‘ํ˜• Grid์‹œ์Šคํ…œ์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.

row / column ๋‘๊ฐ€์ง€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์ง€์›ํ•˜๊ธฐ ๋–„๋ฌธ์— ์‰ฝ๊ฒŒ ์ ์šฉ์‹œํ‚ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ž‘์€ํ™”๋ฉด -> ํฐํ™”๋ฉด ์ˆœ์œผ๋กœ ๋””์ž์ธํ•˜๋Š” ๊ฒƒ์ด ํŽธํ•˜๋ฉฐ,

์ด 24์นธ์œผ๋กœ ๋‚˜๋ˆ„์–ด์ ธ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— 24๋กœ ๋‚˜๋ˆ„์–ด์ ธ์•ผ๋งŒ ํ•˜๋ฉฐ 24๊ฐ€ ๋„˜์–ด๊ฐ€๋ฉด ์•ˆ๋ฉ๋‹ˆ๋‹ค.

<Row gutter={8}>  //column๋“ค ๊ฐ„๊ฒฉ 8px (4px+4px)
        <Col xs={24} md={6}>
          ์™ผ์ชฝ๋ฉ”๋‰ด
        </Col>
        <Col xs={24} md={12}>
          {children}
        </Col>
        <Col xs={24} md={6}>
          ์˜ค๋ฅธ์ชฝ๋ฉ”๋‰ด
        </Col>
 </Row>
 //๋ชจ๋ฐ”์ผ์—์„œ๋Š” 24 24 24
 //md

๋ณดํ†ต ํƒœ๋ธ”๋ฆฟ : sm ๋ชจ๋ฐ”์ผ: xs ์ด๋ ‡๊ฒŒ ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค.

xs

screen < 576px

number | object

-

sm

screen โ‰ฅ 576px

number | object

-

md

screen โ‰ฅ 768px

number | object

-

lg

screen โ‰ฅ 992px

number | object

-

xl

screen โ‰ฅ 1200px

number | object

-

xxl

screen โ‰ฅ 1600px

number | object

-

๋ฌผ๋ก  ๋‚˜์ค‘์— ์ปค์Šคํ…€ ํ•  ์ˆ˜๋„ ์žˆ์Šต๋‹ˆ๋‹ค.

gutter๋Š” grid-gap ๊ณผ ๊ฐ™์€ ์†์„ฑ์ž…๋‹ˆ๋‹ค.

์•„์ดํ…œ ์‚ฌ์ด์˜ ๊ฐ„๊ฒฉ์„ ์˜๋ฏธํ•ฉ๋‹ˆ๋‹ค.

</Col>
  <Col xs={24} md={6}>
     <a
      href="https://ant.design/components/grid/"
      target="_blank"
      rel="noreferrer noopener"
      >
   made by Conrad
   </a>
</Col>

๋กœ๊ทธ์ธ์ฐฝ(์™ผ์ชฝ๋ฉ”๋‰ด)๋ Œ๋”๋ง

์™ผ์ชฝ๋ฉ”๋‰ด์—๋Š” ๋กœ๊ทธ์ธ๊ธฐ๋Šฅ์„ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.

๋ฐฑ์•ค๋“œ ์„œ๋ฒ„๊ฐ€ ์—†๊ธฐ๋•Œ๋ฌธ์— useState๋ฅผ ์ด์šฉํ•œ ์ƒํƒœ๊ด€๋ฆฌ๋กœ ๋”๋ฏธ๋ฐ์ดํ„ฐ๋ฅผ ๋งŒ๋“ค์–ด ์ค๋‹ˆ๋‹ค.

 const [isloggedIn, setIsLoggedIn] = useStatee(false);

์šฐ์„  UserProfile.js / LoginForm.js ๋‘๊ฐ€์ง€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค์–ด์ฃผ์„ธ์š”

Presenter๊ณผ Container๋ฅผ ๋‚˜๋ˆ ์„œ ๊ด€๋ฆฌํ•˜๋Š” ๊ฒƒ์„ ์˜ˆ์ „๋ถ€ํ„ฐ ๋งŽ์ด ์ง„ํ–‰ํ–ˆ์ง€๋งŒ,

๋ฆฌ์•กํŠธํŒ€์ด Hooks ์ดํ›„๋กœ ๋‚˜๋ˆ„๋Š”๊ฑธ ์ถ”์ฒœํ•˜์ง€ ์•Š๋Š”๋‹ค ํ•˜์˜€๊ธฐ์— ํ•œ ํŒŒ์ผ์—์„œ ์ง„ํ–‰ํ•ด๋ด…๋‹ˆ๋‹ค.

LoginForm.js
 <Form>
      <div>
        <label htmlFor="user-id">์•„์ด๋””</label>
        <br />
        <Input name="user-id" required />
      </div>
      <div>
        <label htmlFor="user-password">๋น„๋ฐ€๋ฒˆํ˜ธ</label>
        <br />
        <Input
          name="user-password"
          type="password"
          required
        />
      </div>
      <div>
        <Button type="primary" htmlType="submit" >
          ๋กœ๊ทธ์ธ
        </Button>

        <Link href="/signup"> //ํšŒ์›๊ฐ€์ž…ํŽ˜์ด์ง€๋กœ ๋„˜์–ด๊ฐ€๊ธฐ
          <a>
            <Button>ํšŒ์›๊ฐ€์ž…</Button>
          </a>
        </Link>
      </div>
    </Form>

useState๋ฅผ ์ด์šฉํ•œ Input ์ƒํƒœ๊ด€๋ฆฌ

  const [id, setId] = useState("");
  const [password, setPassword] = useState("");
  const onChangeId = useCallback((e) => {
    setId(e.target.value);
  }, []);
  const onChangePassword = useCallback((e) => {
    setPassword(e.target.value);
  }, []);

์ด์ œ ์ƒํƒœ๋“ค์„ JSX์— ์ ์šฉ์‹œ์ผœ์ฃผ์„ธ์š”

import React, { useState, useCallback } from "react";
import { Form, Input, Button } from "antd";
import Link from "next/link";

export default function LoginForm() {
  const [id, setId] = useState("");
  const [password, setPassword] = useState("");
  const onChangeId = useCallback((e) => {
    setId(e.target.value);
  }, []);
  const onChangePassword = useCallback((e) => {
    setPassword(e.target.value);
  }, []);

  return (
    <Form>
      <div>
        <label htmlFor="user-id">์•„์ด๋””</label>
        <br />
        <Input name="user-id" value={id} onChange={onChangeId} required />
      </div>
      <div>
        <label htmlFor="user-password">๋น„๋ฐ€๋ฒˆํ˜ธ</label>
        <br />
        <Input
          name="user-password"
          type="password"
          value={password}
          onChange={onChangePassword}
          required
        />
      </div>
      <div style={{marginTop:10}}>
        <Button type="primary" htmlType="submit" loading={false}>
          ๋กœ๊ทธ์ธ
        </Button>

        <Link href="/signup">
          <a>
            <Button>ํšŒ์›๊ฐ€์ž…</Button>
          </a>
        </Link>
      </div>
    </Form>
  );
}

AppLayout ์ปดํฌ๋„ŒํŠธ์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋ง ํ•ด์ฃผ์„ธ์š”.

์ด๋ ‡๊ฒŒ ํ™”๋ฉด์ด ์ž˜ ๋‚˜ํƒ€๋‚ฌ์Šต๋‹ˆ๋‹ค.

ํ•œ๊ฐ€์ง€ ์ฃผ์˜ํ•ด์•ผ ํ•  ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์œ„์—์„œ ์ž‘์„ฑํ•œ ์ฝ”๋“œ์ค‘ ์•„๋ž˜ ์ฝ”๋“œ๋ฅผ ๋ด์ฃผ์„ธ์š”

 <div style={{marginTop:10}}>

๋ณดํ†ต css์— ์Šคํƒ€์ผ์„ ์ฃผ๊ธฐ ์œ„ํ•œ ๋ชฉ์ ์œผ๋กœ ๊ฐ„๋‹จํžˆ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๋ฐฉ๋ฒ•์ธ๋ฐ, ์ด๋Š” ํฐ ๋‹ด์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์œ„ div ํƒœ๊ทธ๋ฅผ styled-components๋ฅผ ์ด์šฉํ•ด ๋ฐ”๊ฟ”์ฃผ๊ฒ ์Šต๋‹ˆ๋‹ค.

const ButtonWrapper = styled.div`
  margin-top: 10px;
`;

<ButtonWrapper>

์‚ฌ์‹ค ์„ฑ๋Šฅ์— ํฐ ์ง€์žฅ์„ ์ฃผ์ง€๋Š” ์•Š๊ธฐ๋•Œ๋ฌธ์— ๊ฐ„๋‹จํ•œ ์ž‘์—…์ด๋ฉด ์ธ๋ผ์ธ์Šคํƒ€์ผ์„ ์‚ฌ์šฉํ•˜์…”๋„ ํฌ๊ฒŒ ๋ฌธ์ œ๋  ๊ฒƒ์€ ์—†์Šต๋‹ˆ๋‹ค.

๋ฆฌ๋žœ๋”๋ง

์‚ฌ์‹ค ๋ฆฌ๋žœ๋”๋ง์ด ๋˜๋ฉด ์ฒ˜์Œ๋ถ€ํ„ฐ ๋๊นŒ์ง€ ๋‹ค์‹œ ์‹œ์ž‘๋˜๋Š” ๊ฒƒ์€ ๋งž์Šต๋‹ˆ๋‹ค.

useCallBack, useMemo๋ฅผ ์‚ฌ์šฉํ•ด ์บ์‹ฑํ•˜๊ฒŒ๋˜๋ฉด ๊ทธ๊ฑธ ๋ง‰์•„์ค„ ์ˆ˜ ์žˆ์ฃ .

React์—์„œ๋Š” JSX์—์„œ ๋ฐ”๋€๋ถ€๋ถ„๋งŒ ๋‹ค์‹œ ๋ Œ๋”๋งํ•ด์ค๋‹ˆ๋‹ค.

์ฆ‰ ์ด์ „์˜ ์ปดํฌ๋„ŒํŠธ์™€ ๋น„๊ตํ•ด์„œ ๋ฐ”๋€ ๋ถ€๋ถ„๋งŒ ๋‹ค์‹œ ๊ทธ๋ ค์ค๋‹ˆ๋‹ค.

Virtual DOM ์ฆ‰, ํ•จ์ˆ˜ํ˜• ์ปดํฌ๋„ŒํŠธ ์•ˆ์— return๋˜๋Š” ๋ถ€๋ถ„์„ ๋ฆฌ์•กํŠธ์—์„œ๋Š” ์ฒ˜์Œ์— ํ•œ๋ฒˆ ์‹น ๊ทธ๋ ค์ค€๋’ค,

์ด์ „ ์ปดํฌ๋„ŒํŠธ์™€ ๋‹ค์Œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋น„๊ตํ•ด ๋ฐ”๋€๊ฒŒ ์žˆ์œผ๋ฉด React๋Š” ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ฆฌ๋žœ๋”๋ง ํ•ด์ค๋‹ˆ๋‹ค.

๊ฒฐ๊ตญ ๋ฆฌ๋žœ๋”๋ง์„ ์ ๊ฒŒํ•˜๋ฉด ์„ฑ๋Šฅ์ ์œผ๋กœ ์ข‹๊ฒ ์ฃ ?

Last updated

Was this helpful?