[패스트캠퍼스 수강 후기] 프론트엔드 인강 100% 환급 챌린지 43회차 미션 - 32강 TodoList만들기 1

2 minute read

투두리스트를 위해 먼저 리액트앱을 하나 생성하고 라이브러리를 설치한다.

npx create-react-app todolist-app //이름이 너무 짧아도 안되더라?
yarn add styled-components react-icons //두개 다운받을거면 띄어쓰고 써주면 되더라

그리고 아래와 같이 컴포넌트를 분할해서 만들어 줄 것이다.
컴포넌트분할 컴포넌트분할 컴포넌트분할 컴포넌트분할 컴포넌트분할

자세한 코드는 벨로퍼트의 위키를 참고하도록 하자.
이제 styled-components쓰는 것과 컴포넌트 분할에 대해서는 어느정도 이해가 간다. 대충 구조도 이제 혼자서 잘 짜고 스타일링도 가능할 것 같다. 컴포넌트 별로 작성한 코드를 살펴보자.

App.js

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

const GlobalStyle = createGlobalStyle`
  body{
    background: #e9ecef;
  }
`;
function App() {
  return (
    <>
      <GlobalStyle />
      <TodoTemplate>
        <TodoHead />
        <TodoList />
        <TodoCreate />
      </TodoTemplate>
    </>
  );
}

export default App;

전체적으로는 이렇다. GlobalStyle은 전역적으로 적용하는 스타일을 createGlobalStyle로 정의하는 것이라고 한다. 이제 각 컴포넌트별 코드를 보도록 하자.

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 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;

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;
  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>2020 9 21</h1>
      <div className="day">월요일</div>
      <div className="tasks-left">할일 2 남음</div>
    </TodoHeadBlock>
  );
}

export default TodoHead;

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;
  background: transparent;
`;

function TodoList() {
  return (
    <TodoListBlock>
      <TodoItem text="프로젝트 생성하기" done={true} />
      <TodoItem text="프로젝트 생성하기" done={true} />
      <TodoItem text="프로젝트 생성하기" done={false} />
      <TodoItem text="프로젝트 생성하기" done={false} />
    </TodoListBlock>
  );
}

export default TodoList;

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: flex;
  align-items: center;
  justify-content: center;

  position: absolute;
  left: 50%;
  bottom: 0px;
  transform: translate(-50%, 50%); /* 자신의 너비의 반만큼 */

  font-size: 60px;
  color: white;
  border-radius: 40px;

  border: none;
  outline: none;
  transition: 0.2s all;

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

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

const InserForm = styled.div`
  background: #f8f9fa;
  padding: 32px;
  padding-bottom: 72px;
  border-radius: 0 0 16px 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>
          <InserForm>
            <Input placeholder="할일을 입력 후 엔터를 눌러주세요." autoFocus />
          </InserForm>
        </InsertFormPositioner>
      )}
      <CircleButton onClick={onToggle} open={open}>
        <MdAdd />
      </CircleButton>
    </>
  );
}

export default TodoCreate;

각 컴포넌트별로 이렇게 작성해주고 렌더링 해보면 껍데기는 잘 돌아간다.
이제 문제는 상태관리.. useState로 상태 관리하는게 아직 익숙치 않다.. 내일 마저 더 손에 익혀봐야겠다.

오늘은 여기까지..
시청 영상 32강 01~03까지
수강인증이미지 수강인증이미지 수강인증이미지 프론트엔드 개발 올인원 패키지 with React Online. 👉 https://bit.ly/31Cf1hp

Comments