[React] TodoList - 컴포넌트 만들기

2022. 4. 21. 13:32·개발 (Development)/React

Visual Studio Code 터미널에서 create-react-app 을 사용하여 새로운 프로젝트를 만든다.

  • npm 버전이 맞지 않을 경우 재설치를 하거나 nvm list에서 nvm 버전을 바꾼다.
  • create-react-app 에러 발생 시 지우고 재설치 해본다.
$ npx create-react-app mashup-todolist

 

해당 디렉토리 이동 후 react-icons와 styled-component 라이브러리를 설치한다.

$ cd mashup-todolist
$ yarn add react-icons styled-components

그리고 터미널에서 해당 디렉토리를 열고  yarn start  를 입력하여 개발 서버를 실행한다.

만들어야 할 컴포넌트 목록

TodoTemplate

우리가 만들 TodoList의 레이아웃을 설정하는 컴포넌트. 가장 상위 컴포넌트

TodoHead

날짜와 요일을 보여주고, 앞으로 해야할 일이 몇 개 남았는지 출력

TodoList

할 일에 대한 정보가 들어있는 todos 배열을 내장함수  map  을 사용하여 여러개의 TodoItem 컴포넌트를 렌더링 해준다.

TodoItem

갈 할 일에 대한 정보를 렌더링 해주는 컴포넌트. 좌측에 있는 원을 누르면 할 일의 완료 여부를 toggle. 할 일이 완료됐을 때 좌측에 체크가 나타나고 색상이 연해진다. 그리고 마우스를 올리면 휴지통 아이콘이 나타나고 아이콘 클릭 시 항목 삭제

TodoCreate

새로운 할 일을 등록할 수 있게 해주는 컴포넌트. TodoTemplate의 하단에 초록색 원 버튼을 렌더링하고, 이를 클릭하면 할 일을 입력할 수 있는 폼이 나타난다. 버튼을 다시 누르면 폼이 사라진다.

페이지에 회색 배경색상 적용

페이지에 회색( #e9ecef 또는 lightgray ) 배경색상 적용. 페이지의 배경색상 설정 시  body 태그에 CSS를 적용해주면 된다. 적용하기 위해서 index.css에서 해도 무방하지만, 여기서는 styled-components를 사용하여 스타일을 적용한다.

styled-components에서 특정 컴포넌트를 만들어서 스타일링 하는게 아니라 글로벌 스타일을 추가하고 싶을 때는  createGlobalStyle 을 사용한다. 이 함수를 사용하면 컴포넌트가 만들어지는데, 이 컴포넌트를 렌더링하면 된다.

App.js를 다음과 같이 수정한다.

App.js

import React from 'react';
import { createGlobalStyle } from 'styled-components';

const GlobalStyle = createGlobalStyle`
  body {
    background: #e9ecef; // 또는 lightgray
  }
`;

function App() {
  return (
    <>
      <GlobalStyle />
      <div>안녕하세요</div>
    </>
  );
}

export default App;

위와 같이 회색 배경이 나타난다.

TodoTemplate 만들기

TodoTemplate 컴포넌트를 만들어서 중앙에 정렬된 흰색 박스를 보여준다. src 디렉터리에 components 디렉터리를 만들고, 그 안에 TodoTemplate.js를 만든다.

components/TodoTemplate.js

import React from 'react';
import styled from 'styled-components';

const TodoTemplateBlock = styled.div`
  width: 512px;
  height: 768px;

  position: relative; /* 추후 박스 하단에 추가 버튼을 위치시키기 위한 설정 */
  background: white;
  border-radius: 16px;
  box-shadow: 0 0 8px 0 rgba(0, 0, 0, 0.04);

  margin: 0 auto; /* 페이지 중앙에 나타나도록 설정 */

  margin-top: 96px;
  margin-bottom: 32px;
  display: flex;
  flex-direction: column;
`;

function TodoTemplate({ children }) {
  return <TodoTemplateBlock>{children}</TodoTemplateBlock>;
}

export default TodoTemplate;

작성 후 이 컴포넌트를 App.js에서 렌더링한다.

App.js

import React from 'react';
import { createGlobalStyle } from 'styled-components';
import TodoTemplate from './components/TodoTemplate';

const GlobalStyle = createGlobalStyle`
  body {
    background: #e9ecef;
  }
`;

function App() {
  return (
    <>
      <GlobalStyle />
      <TodoTemplate>안녕하세요</TodoTemplate>
    </>
  );
}

export default App;

흰 색 박스가 출력된다.

TodoHead 만들기

이 컴포넌트는 오늘의 날짜, 요일, 남은 할 일 개수를 보여준다.

components/TodoHead.js

import React from 'react';
import styled from 'styled-components';

const TodoHeadBlock = styled.div`
  padding-top: 48px;
  padding-left: 32px;
  padding-right: 32px;
  padding-bottom: 24px;
  border-bottom: 1px solid #e9ecef;
  h1 {
    margin: 0;
    font-size: 36px;
    color: #343a40;
  }
  .day {
    margin-top: 4px;
    color: #868e96;
    font-size: 21px;
  }
  .tasks-left {
    color: #20c997;
    font-size: 18px;
    margin-top: 40px;
    font-weight: bold;
  }
`;

function TodoHead() {
  return (
    <TodoHeadBlock>
      <h1>2019년 7월 10일</h1>
      <div className="day">수요일</div>
      <div className="tasks-left">할 일 2개 남음</div>
    </TodoHeadBlock>
  );
}

export default TodoHead;

이 컴포넌트에서는 TodoHeadBlock 안에 들어있는 내용들에 대하여 일일히 컴포넌트를 만드는 대신에 그냥 일반 HTML 태그를 사용하고, TodoHeadBlock의 스타일에서 CSS Selector를 사용하여 스타일링 했다.

이 컴포넌트를 App에서 렌더링한다.

App.js

import React from 'react';
import { createGlobalStyle } from 'styled-components';
import TodoTemplate from './components/TodoTemplate';
import TodoHead from './components/TodoHead';

const GlobalStyle = createGlobalStyle`
  body {
    background: #e9ecef;
  }
`;

function App() {
  return (
    <>
      <GlobalStyle />
      <TodoTemplate>
        <TodoHead />
      </TodoTemplate>
    </>
  );
}

export default App;

TodoList 만들기

components/TodoList.js

import React from 'react';
import styled from 'styled-components';

const TodoListBlock = styled.div`
  flex: 1;
  padding: 20px 32px;
  padding-bottom: 48px;
  overflow-y: auto;
  background: gray; /* 사이즈 조정이 잘 되고 있는지 확인하기 위한 임시 스타일 */
`;

function TodoList() {
  return <TodoListBlock>TodoList</TodoListBlock>;
}

export default TodoList;

사이즈 관련 설정만 했다.  flex: 1  스타일을 설정함으로써 자신이 차지할 수 있는 영역을 꽉 채우도록 설정했다. 이를 확인하기 위해 회색 배경 설정.

이 컴포넌트를 App에서 렌더링한다.

App.js

import React from 'react';
import { createGlobalStyle } from 'styled-components';
import TodoTemplate from './components/TodoTemplate';
import TodoHead from './components/TodoHead';
import TodoList from './components/TodoList';

const GlobalStyle = createGlobalStyle`
  body {
    background: #e9ecef;
  }
`;

function App() {
  return (
    <>
      <GlobalStyle />
      <TodoTemplate>
        <TodoHead />
        <TodoList />
      </TodoTemplate>
    </>
  );
}

export default App;

TodoList가 회색으로 잘 나타났다면,  background: gray  속성을 없애준다.

TodoItem 만들기

각 할 일 항목들을 보여주는 TodoItem 컴포넌트를 만든다. 이 컴포넌트에서는 react-icons 에서 MdDone 과 MdDelete 아이콘을 사용한다.

TodoItem.js

import React from 'react';
import styled, { css } from 'styled-components';
import { MdDone, MdDelete } from 'react-icons/md';

const Remove = styled.div`
  display: flex;
  align-items: center;
  justify-content: center;
  color: #dee2e6;
  font-size: 24px;
  cursor: pointer;
  &:hover {
    color: #ff6b6b;
  }
  display: none;
`;

// Component Selector 기능 : TodoItemBlock 위에 커서가 있을 떄 Remove 컴포넌트를 보여준다.
const TodoItemBlock = styled.div`
  display: flex;
  align-items: center;
  padding-top: 12px;
  padding-bottom: 12px;
  &:hover {
    ${Remove} {
      display: initial;
    }
  }
`;

const CheckCircle = styled.div`
  width: 32px;
  height: 32px;
  border-radius: 16px;
  border: 1px solid #ced4da;
  font-size: 24px;
  display: flex;
  align-items: center;
  justify-content: center;
  margin-right: 20px;
  cursor: pointer;
  ${props =>
    props.done &&
    css`
      border: 1px solid #38d9a9;
      color: #38d9a9;
    `}
`;

const Text = styled.div`
  flex: 1;
  font-size: 21px;
  color: #495057;
  ${props =>
    props.done &&
    css`
      color: #ced4da;
    `}
`;

function TodoItem({ id, done, text }) {
  return (
    <TodoItemBlock>
      <CheckCircle done={done}>{done && <MdDone />}</CheckCircle>
      <Text done={done}>{text}</Text>
      <Remove>
        <MdDelete />
      </Remove>
    </TodoItemBlock>
  );
}

export default TodoItem;

[참고] Component Selector

이 컴포넌트를 TodoList에서 렌더링한다.

components/TodoList.js

import React from 'react';
import styled from 'styled-components';
import TodoItem from './TodoItem';

const TodoListBlock = styled.div`
  flex: 1;
  padding: 20px 32px;
  padding-bottom: 48px;
  overflow-y: auto;
`;

function TodoList() {
  return (
    <TodoListBlock>
      <TodoItem text="프로젝트 생성하기" done={true} />
      <TodoItem text="컴포넌트 스타일링 하기" done={true} />
      <TodoItem text="Context 만들기" done={false} />
      <TodoItem text="기능 구현하기" done={false} />
    </TodoListBlock>
  );
}

export default TodoList;

각 항목이 잘 나타나는지, 커서를 올렸을 때, 삭제 아이콘이 나타나는지 확인한다.

TodoCreate 만들기

이 컴포넌트에서는 react-icons의 MdAdd를 사용한다.

그리고  useState 를 사용해서 토글할 수 있는 open 값을 관리하며, 이 값이  true 일 때는 아이콘을 45도 돌려서 X 모양이 보이게 한 후 버튼 색상을 빨간색으로 바꾼다. 그리고 할 일을 입력할 수 있는 폼도 보여준다.

components/TodoCreate.js

import React, { useState } from 'react';
import styled, { css } from 'styled-components';
import { MdAdd } from 'react-icons/md';

const CircleButton = styled.button`
  background: #38d9a9;
  &:hover {
    background: #63e6be;
  }
  &:active {
    background: #20c997;
  }

  z-index: 5;
  cursor: pointer;
  width: 80px;
  height: 80px;
  display: block;
  align-items: center;
  justify-content: center;
  font-size: 60px;
  position: absolute;
  left: 50%;
  bottom: 0px;
  transform: translate(-50%, 50%);
  color: white;
  border-radius: 50%;
  border: none;
  outline: none;
  display: flex;
  align-items: center;
  justify-content: center;

  transition: 0.125s all ease-in;
  ${props =>
    props.open &&
    css`
      background: #ff6b6b;
      &:hover {
        background: #ff8787;
      }
      &:active {
        background: #fa5252;
      }
      transform: translate(-50%, 50%) rotate(45deg);
    `}
`;

const InsertFormPositioner = styled.div`
  width: 100%;
  bottom: 0;
  left: 0;
  position: absolute;
`;

const InsertForm = styled.form`
  background: #f8f9fa;
  padding-left: 32px;
  padding-top: 32px;
  padding-right: 32px;
  padding-bottom: 72px;

  border-bottom-left-radius: 16px;
  border-bottom-right-radius: 16px;
  border-top: 1px solid #e9ecef;
`;

const Input = styled.input`
  padding: 12px;
  border-radius: 4px;
  border: 1px solid #dee2e6;
  width: 100%;
  outline: none;
  font-size: 18px;
  box-sizing: border-box;
`;

function TodoCreate() {
  const [open, setOpen] = useState(false);

  const onToggle = () => setOpen(!open);

  return (
    <>
      {open && (
        <InsertFormPositioner>
          <InsertForm>
            <Input autoFocus placeholder="할 일을 입력 후, Enter 를 누르세요" />
          </InsertForm>
        </InsertFormPositioner>
      )}
      <CircleButton onClick={onToggle} open={open}>
        <MdAdd />
      </CircleButton>
    </>
  );
}

export default TodoCreate;

이 컴포넌트를 App.js에서 렌더링한다.

App.js

import React from 'react';
import { createGlobalStyle } from 'styled-components';
import TodoTemplate from './components/TodoTemplate';
import TodoHead from './components/TodoHead';
import TodoList from './components/TodoList';
import TodoCreate from './components/TodoCreate';

const GlobalStyle = createGlobalStyle`
  body {
    background: #e9ecef;
  }
`;

function App() {
  return (
    <>
      <GlobalStyle />
      <TodoTemplate>
        <TodoHead />
        <TodoList />
        <TodoCreate />
      </TodoTemplate>
    </>
  );
}

export default App;

TodoCreate 버튼을 눌러서 UI가 바뀌는지 확인한다.

 

출처

https://react.vlpt.us/mashup-todolist/01-create-components.html

 

1. 컴포넌트 만들기 · GitBook

1. 컴포넌트 만들기 투두리스트의 기능을 구현하기 전에, 우리 프로젝트에서 필요한 모든 컴포넌트들의 UI 를 미리 만들어보겠습니다. 우선 create-react-app 을 사용하여 새로운 프로젝트를 만들어

react.vlpt.us

 

반응형

'개발 (Development) > React' 카테고리의 다른 글

[React] npm install 시 의존성 충돌 오류 해결 방법  (0) 2025.06.01
[React] 프로젝트 환경 설정  (0) 2022.04.04
'개발 (Development)/React' 카테고리의 다른 글
  • [React] npm install 시 의존성 충돌 오류 해결 방법
  • [React] 프로젝트 환경 설정
LoopThinker
LoopThinker
모르는 것을 알아가고, 아는 것을 더 깊게 파고드는 공간
  • LoopThinker
    CodeMemoir
    LoopThinker
  • 전체
    오늘
    어제
    • 분류 전체보기 (231)
      • 개발 (Development) (165)
        • Algorithm (1)
        • Angular (1)
        • AWS (6)
        • DeepSeek (2)
        • Docker (7)
        • Git (3)
        • Java (34)
        • JavaScript (4)
        • Kafka (5)
        • Kubernetes (4)
        • Linux (7)
        • PostgreSQL (38)
        • Python (31)
        • React (3)
        • TypeScript (3)
        • Vue.js (5)
        • General (11)
      • 데이터 분석 (Data Analysis) (1)
      • 알고리즘 문제 풀이 (Problem Solving.. (27)
      • 자격증 (Certifications) (24)
        • ADsP (14)
        • 정보처리기사 (4)
        • Linux Master (5)
        • SQLD (1)
      • 기술 동향 (Tech Trends) (11)
      • 기타 (Others) (3)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    데이터분석
    python
    백준온라인저지
    JSON
    백준알고리즘
    Linux
    Linux master
    ADsP
    리눅스 마스터 2급
    java
    리눅스 마스터 2급 2차
    AWS
    javascript
    백준자바
    백준
    Kubernetes
    pandas
    MyBatis
    deepseek
    JPA
    오답노트
    PostgreSQL
    Vue.js
    Kafka
    DevOps
    Spring boot
    timescaledb
    springboot
    자바
    docker
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.3
LoopThinker
[React] TodoList - 컴포넌트 만들기
상단으로

티스토리툴바