2019. 8. 29. 17:07

1. Component 계획

다음과 같이 4개의 컴포넌트로 To-do list 를 구성 하려고 한다.

  • PageTemplate : UI의 전체 틀을 설정한다.
  • InputTodo : 일정을 추가할때 사용하는 컴포넌트이다. input 폼과 추가 버튼이 있다.
  • TodoItem : To-do list의 아이템 하나 하나가 된다.
  • TodoList : 데이터를 TodoItem 컴포넌트로 리스트를 만드는 역할을 한다.

 

2. Component 생성하기

 

3. PageTemplate

//src/components/PageTemplate.js

import React from 'react'; 
import styles from './PageTemplate.scss';
import classNames from 'classnames/bind';

const cx = classNames.bind(styles);

const PageTemplate = ({ children }) => {
    return (
        <div className={cx('page-template')}>
            <h1>To-do List</h1>
            <div className={cx('content')}> {children} </div>
        </div>)
};

export default PageTemplate;

import styles from './PageTemplate.scss'; 로 스타일을 import 한뒤 classNames 패키지로 bind한다.

To-do List의 가장 큰 기본틀을 구성하며 { children } 으로 자식요소들을 로드.

 

/*src/components/PageTemplate/PageTemplate.scss*/

@import "../../styles/utils";

.page-template {

margin-top: 5rem;

margin-left: auto;

margin-right: auto;

width: 500px;

background: white;

box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px, rgba(0,0,0,0.23);

padding-top: 2rem;



@media (max-width: 768px) {

margin-top: 1rem;

width: calc(100% - 2rem);

}

h1{

ext-align: center;

font-size: 4rem;

font-weight: 300;

margin: 0;

}

.content {

margin-top: 2rem;

}

}

 

//src/components/PageTemplate/index.js

export { default } from './PageTemplate';

/ndex.js 는 default 소스가 된다.

따라서 위와 같이 index.js 를 작성해 주면 상위 컴포넌트인 App.js에서 './PageTemplate/PageTemplate.js' 가 아닌 './PageTemplate' 로 import 할 수 있다.

 

4. InputTodo

//src/components/InputToto/InputTodo.js

import React from 'react';
import styles from './InputTodo.scss';
import classNames from 'classnames/bind';

const cx = classNames.bind(styles);

const InputTodo = ({ value, onChange, onInsert }) => {
    const handleKeyPress = (e) => {
        if (e.key === 'Enter') {
            onInsert();
        }
    };

    return (
        <div className={cx('todo-input')}>
            <input onChange={onChange} value={value} onKeyPress={handleKeyPress} />
            <div className={cx('add-button')} onClick={onInsert}>추가</div>
        </div>
    )
};

export default InputTodo;

-이 컴포너트는 props를 3개 받는다.

  • value : input 값으로 설정
  • onChange : input 내용에 변경이 있을때 사용하는 이벤트
  • onInsert : 추가 버튼을 눌렀을 때 실행하는 이벤트

-키보드 Enter 키 입력 이벤트를 위해서 handleKeyPress 메서드도 생성한다.

 

/*src/components/InputTodo/InputTodo.scss*/

@import "../../styles/utils";

.todo-input {
border-top: 1px solid $oc-gray-2;
border-bottom: 1px solid $oc-gray-2;
display: flex;
padding: 1rem;

input{
flex: 1;
font-size: 1.1rem;
outline: none;
border: none;
background: transparent;
border-bottom: 1px solid $oc-gray-4;
&:focus {
border-bottom: 1px solid $oc-cyan-6;
}
}

.add-button {
width: 5rem;
height: 2rem;
margin-left: 1rem;
border: 1px solid $oc-green-7;
color: $oc-green-7;
font-weight: 500;
font-size: 1.1rem;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
&:hover {
background: $oc-green-7;
color: white;
}
&:active {
background: $oc-green-8;
}
}
}

 

//src/components/InputTodo/index.js

export { default } from './InputTodo'

 

5. TodoItem

일정 정보를 렌더링 하는 TodoItem 컴포넌트이다.

//src/components/TodoItem/TodoItem.js

import React, { Component } from 'react';
import styles from './TodoItem.scss';
import classNames from 'classnames/bind';

const cx = classNames.bind(styles);

class TodoItem extends Component {
    render() {
        const { done, children, onToggle, onRemove } = this.props;
        return (
            <div className={cx('todo-item')} onClick={onToggle}>
                <input className={cx('tick')} type="checkbox" checked={done} readOnly />
                <div className={cx('text', { done })}>{children}</div>
                <div className={cx('delete')} onClick={onRemove}>[지우기]</div>
            </div>
        );
    }
}

export default TodoItem;
  • done : 해당 일정이 완료했는지 체크
  • children : 자식요소 (일정 내용)
  • onToggle : 일정 완료/미완료 토글
  • onRemove : 해당 일정 삭제
  • const {done, children, onToggle, onRemove} = this.props; 비구조화 할당을 사용하여 아래에서 props를 사용할때 this.props.onToggle 과 같이 메서드 앞에 this.props 를 붙이는것을 생략할 수 있다.
/*src/components/TodoItem/TodoItem.scss*/

@import "../../styles/utils";

.todo-item {
padding: 1rem;
display: flex;
align-items: center;
cursor: pointer;
.tick {
margin-left: 1rem;
}
.text {
flex: 1;
word-break: break-all;
&.done {
text-decoration: line-through;
}
}
.delete {
margin-left: 1rem;
color: $oc-red-7;
font-size: 0.8rem;
&:hover {
color: $oc-red-5;
text-decoration: underline;
}
}
&:nth-child(odd) {
background: $oc-gray-0;
}
&:hover {
background: $oc-gray-1;
}

}

/*컴포넌트 사이에 위쪽 테두리를 설정*/
.todo-item + .todo-item {
border-top: 1px solid $oc-gray-1;
}

 

src/components/TodoItem/index.js

export { default } from './TodoItem';

6. TodoList

TodoList 컴포넌트는 데이터 배열을 컴포넌트 배열로 변환하여 렌더링 하는 역할만 한다. 데이터를 컴포넌트 배열로 변환하는 코드전에 더미 데이터를 넣어 컴포넌트가 정상적으로 렌더링 되는지 테스트 해본다.

//src/components/TodoList/TodoList.js

import React, { Component } from 'react';
import TodoItem from '../TodoItem';

class TodoList extends Component {
    render() {
        return (
            <div>
                <TodoItem done>첫번째 할일</TodoItem>
                <TodoItem>두번째 할일</TodoItem>
            </div>
        );
    }
}

export default TodoList;

 

//src/components/TodoList/index.js

export { default } from './TodoList';

7. App.js

//src/components/App.js

import React, { Component } from 'react';
import PageTemplate from './PageTemplate';
import InputTodo from './InputTodo';
import TodoList from './TodoList';

class App extends Component {
    render() {
        return (
            <PageTemplate>
                <InputTodo />
                <TodoList />
            </PageTemplate>
        );
    }
}

export default App;

 

App.js 에서 해당 컴포넌트를 로드하고 npm run start 명령어로 개발서버를 실행해보자.

정상적으로 컴포넌트들이 렌더링 되고 UI가 구성되는것을 확인할 수 있다.

 

 

출처:https://juicyjusung.github.io/2019/03/25/react/To-do-list-%EB%A7%8C%EB%93%A4%EA%B8%B0-2-UI-%EB%94%94%EC%9E%90%EC%9D%B8-%EA%B5%AC%EC%84%B1-%EB%B0%8F-%EC%BB%B4%ED%8F%AC%EB%84%8C%ED%8A%B8-%EC%83%9D%EC%84%B1/

Posted by yongminLEE