본문 바로가기
JavaScript/React

React) 일정 관리 웹 애플리케이션 만들기 - 1 (프로젝트 준비 및 UI 구성)

by 박채니 2022. 11. 19.
안녕하세요, 코린이의 코딩 학습기 채니 입니다.
[리액트를 다루는 기술]의 책을 참고하여 포스팅한 개인 공부 내용입니다.

 

프로젝트 준비하기

 

프로젝트 생성 및 필요한 라이브러리 설치

 

$ yarn create react-app todo-app

 create-react-app을 이용해 프로젝트를 생성해주었습니다.

 

$ cd todo-app

$ yarn add sass classnames react-icons

해당 디럭토리로 이동하여 필요한 라이브러리를 설치해줍니다.

※ react-icons

리액트에서 다양하고 예쁜 아이콘을 사용할 수 있는 라이브러리 (SVG 형태로 이루어진 아이콘을 컴포넌트처럼 쉽게 사용)

 

Prettier 설정

 

코드 스타일을 깔끔하게 정리하기 위해 Prettier를 설정해줍니다.

 

.prettierrc (프로젝트 최상위 디렉토리에 생성)

{
    "singleQuote": true,
    "semi": true,
    "useTabs": false,
    "tabWidth": 2,
    "trailingComma": "all",
    "printWidth": 80
}

 

index.css 수정

 

index.css

body {
  margin: 0;
  padding: 0;
  background: #e9ecef;
}

배경색을 회색으로 설정해주었습니다.

 

App 컴포넌트 초기화

 

App.js

const App = () => {
  return (
    <div>Todo App을 만들어보자!!</div>
  )
}

export default App;

기본적인 설정을 끝낸 후 yarn start로 개발 서버를 구동해보겠습니다.

정상 출력되는 것을 확인하였다면, UI 개발을 시작해보겠습니다.

 


UI 구성하기

 

해당 프로젝트에서 생성할 컴포넌트는 총 4개 입니다.

 

  • TodoTemplate : 화면을 가운데에 정렬시켜 주며, 앱 타이틀을 보여줌. children으로 내부 JSX를 props로 받아와 렌더링
  • TodoInsert : 새로운 항목을 입력하고 추가. state를 통해 인풋 상태 관리
  • TodoListItem : 각 할 일 항목에 대한 정보를 보여줌. todo 객체를 props로 받아와 상태에 따라 다른 스타일의 UI 보여줌
  • TodoList : todos 배열을 props로 받아 온 후, 이를 map을 이용해 여러 개의 TodoListItem 컴포넌트 반환

해당 컴포넌트들은 src 디렉터리에 components라는 디렉터리를 생성하여 저장하겠습니다. (일종의 관습)

 

TodoTemplate 만들기

 

TodoTemplate.js

import './TodoTemplate.scss';

const TodoTemplate = ({ children }) => {
    return (
        <div className="TodoTemplate">
            <div className="app-title">일정 관리</div>
            <div className="content">{children}</div>
        </div>
    )
}

export default TodoTemplate;

컴포넌트 사이에 있는 내용을 children으로 받아와 렌더링해주겠습니다.

 

App.js

import TodoTemplate from "./components/TodoTemplate";

const App = () => {
  return (
    <TodoTemplate>Todo App을 만들어보자!!</TodoTemplate>
  )
}

export default App;

이 때 import 구문을 따로 작성하지 않고, 바로 컴포넌트를 사용하려고 하면 자동 완성 기능이 나타나고 Enter를 누르면 import 구문이 생성됩니다.

다만 TodoTemplate.js 컴포넌트가 다른 탭에 열려있지 않으면 작동 되지 않으므로,

추후 열려있지 않아도 자동 완성을 이용하기 위해 jsconfig.json 파일을 만들어주겠습니다.

 

jsconfig.json (프로젝트 최상위 디렉터리)

{
    "compilerOptions": {
        "target": "es2020"
    }
}

ctrl + space하면 자동 완성 박스가 나타나고 Enter를 누르면 위와 같은 코드가 자동 완성 됩니다.

위와 같이 스타일 적용이 안되어있는 화면이 나타날 것이고, 스타일을 적용해보겠습니다.

 

TodoTemplate.scss

.TodoTemplate {
    width: 512px;
    // width가 주어진 상태에서 좌우 중앙 정렬
    margin-left: auto;
    margin-right: auto;
    margin-top: 6rem;
    border-radius: 4px;
    overflow: hidden;

    .app-title {
        background: #22b8cf;
        color: white;
        height: 4rem;
        font-size: 1.5rem;
        font-weight: bold;
        display: flex;
        justify-content: center;
        align-items: center;
    }

    .content {
        background: white;
    }
}

※ Flexbox 관련 사이트

https://flexboxfroggy.com/#ko

 

Flexbox Froggy

A game for learning CSS flexbox

flexboxfroggy.com

 

 

TodoInsert 만들기

 

TodoInsert.js

import { MdAdd } from 'react-icons/md';
import './TodoInsert.scss';

const TodoInsert = () => {
    return (
        <form className='TodoInsert'>
            <input placeholder="할 일을 입력하세요" />
            <button type="submit">
                <MdAdd />
            </button>
        </form>
    )
}

export default TodoInsert;

여기서 react-icons를 사용했는데 이는 아래 url에 접속하면 수많은 아이콘과 이름이 나타나게 됩니다.

사용하고 싶은 아이콘을 선택 후, import 구문을 이용해 불러와서 컴포넌트처럼 사용합니다.

import { 아이콘 이름 } from 'react-icons/md';

https://react-icons.github.io/react-icons/icons?name=md 

 

React Icons

 

react-icons.github.io

 

App.js

import TodoInsert from "./components/TodoInsert";
import TodoTemplate from "./components/TodoTemplate";

const App = () => {
  return (
    <TodoTemplate>
      <TodoInsert />
    </TodoTemplate>
  )
}

export default App;

 

TodoInsert.scss

.TodoInsert {
    display: flex;
    background: #495057;
    
    input {
        // 기본 스타일 초기화
        background: none;
        outline: none;
        border: none;
        padding: 0.5rem;
        font-size: 1.125rem;
        line-height: 1.5;
        color: white;
        &::placeholder {
            color: #dee2e6;
        }
        //버튼을 제외한 영역 모두 차지하기
        flex: 1;
    }
    
    button {
        // 기본 스타일 초기화
        background: none;
        outline: none;
        border: none;
        background: #868e96;
        color: white;
        padding-left: 1rem;
        padding-right: 1rem;
        font-size: 1.5rem;
        display: flex;
        align-items: center;
        cursor: pointer;
        transition: 0.1s background ease-in;
        &:hover {
            background: #adb5ba;
        }
    }
}

 

TodoListItem과 TodoList 만들기

 

TodoListItem.js

import { MdCheckBox, MdRemoveCircleOutline, MdCheckBoxOutlineBlank } from 'react-icons/md';
import './TodoListItem.scss';

const TodoListItem = () => {
    return (
        <div className='TodoListItem'>
            <div className='checkbox'>
                <MdCheckBoxOutlineBlank />
                <div className='text'>할 일</div>
            </div>
            <div className='remove'>
                <MdRemoveCircleOutline />
            </div>
        </div>
    );
}

export default TodoListItem;

 

TodoList.js

import './TodoList.scss';
import TodoListItem from './TodoListItem';

const TodoList = () => {
    return (
        <div className='TodoList'>
            <TodoListItem />
            <TodoListItem />
            <TodoListItem />
        </div>
    )
}

export default TodoList;

생성한 TodoListItem을 TodoList에서 보여줍니다.

이 때 우선은 하드 코딩으로 보여주지만 추후 기능을 추가하고 다양한 데이터를 전달하도록 하겠습니다.

 

App.js

import TodoInsert from "./components/TodoInsert";
import TodoList from "./components/TodoList";
import TodoTemplate from "./components/TodoTemplate";

const App = () => {
  return (
    <TodoTemplate>
      <TodoInsert />
      <TodoList />
    </TodoTemplate>
  )
}

export default App;

이제 스타일 적용을 해보겠습니다.

 

TodoList.scss

.TodoList {
    min-height: 320px;
    max-height: 513px;
    overflow-y: auto;
}

 

TodoListItem.scss

.TodoListItem {
    padding: 1rem;
    display: flex;
    align-items: center; // 세로 중앙 정렬
    &:nth-child(even) { // 짝수 자식 요소
        background: #f8f9fa;
    }

    .checkbox {
        cursor: pointer;
        flex: 1;
        display: flex;
        align-items: center;

        // 아이콘
        svg {
            font-size: 1.5rem;
        }
        .text {
            margin-left: 0.5rem;
            flex: 1;
        }
        // 체크되었을 때 보여줄 스타일
        &.checked {
            svg {
                color: #22b8cf;
            }
            .text {
                color: #adb5bd;
                text-decoration: line-through;
            }
        }
    }

    .remove {
        display: flex;
        align-items: center;
        font-size: 1.5rem;
        color: #ff6b6b;
        cursor: pointer;
        &:hover {
            color: #ff8787;
        }
    }

    // 엘리먼트 사이사이에 테두리
    & + & {
        border-top: 1px solid #dee2e6;
    }
}

컴포넌트 틀과 스타일을 끝냈습니다.