본문 바로가기
프로젝트/Todo

간단한 TodoList만들기 - (2)

by 코라제이 2020. 1. 13.

1편 에 이어서 시작!

 

1편에서 만들어 놨던 각각의 컴포넌트들을 App.js에 추가 해준 컴포넌트들에서 각각의 리스트 아이템을 보여주기 위해서  훅을 사용한다.

 

import React, { useState } from 'react';
import './App.css'
import TodoTemplate from './components/TodoTemplate';
import TodoInsert from './components/TodoInsert';
import TodoList from './components/TodoList';

const App = () => {

  const [todos, setTodos] = useState([
    {
      id:1,
      contents: '리액트 연습',
      check: true
    },
    {
      id:2,
      contents: 'todolist',
      check: true
    }
  ]);

  return (
    <div>
      <TodoTemplate  >
        <TodoInsert />
        <TodoList todos={todos}/>
      </TodoTemplate>
    </div>
  );
};

export default App;

 

그러고 나서 TodoList, TodoListItem을 아래와 같이 바꿔준다.

 

TodoList

import React from "react";
import "./TodoList.css";
import TodoListItem from "./TodoListItem";

const TodoList = ({ todos }) => {
  return (
    <div className="TodoList">
      {todos.map(todo => (
        <TodoListItem key={todo.id} todo={todo} />
      ))}
    </div>
  );
};

export default TodoList;

TodoListItem

import React from 'react';
import './TodoListItem.css';

const TodoListItem = ({todo}) => {
    const {contents, check} =todo;
    return (
        <div className="TodoListItem">
            <div className="complate"> 완료 </div>
            <div className="todo">{contents}</div>
            <div className="delete"> 삭제 </div>
        </div>
    );
};

export default TodoListItem;

 

먼저 TodoList에서 map을 사용하는 건 불변성 유지를 해줘 야하기 때문이다.

 

위와 같이 되었다.  이제 TodoInsert에 추가된 내용을 전달받는 함할 수 있게 만들어주기 위해서 App.js에 새로운 함수를 만들어서 전달해주자.

import React, { useState, useCallback, useRef } from 'react';
import './App.css'
import TodoTemplate from './components/TodoTemplate';
import TodoInsert from './components/TodoInsert';
import TodoList from './components/TodoList';

const App = () => {

  const [todos, setTodos] = useState([
    {
      id:1,
      contents: '리액트 연습',
      check: true
    },
    {
      id:2,
      contents: 'todolist',
      check: true
    },
  ]);

  let nextId = useRef(3);
  
  const insert = useCallback(contents=>{
    const todo = {
      id:nextId.current,
      contents,
      check: true
    };
    setTodos(todos=>todos.concat(todo));
    nextId.current += 1;
  },[])
  
  return (
    <div>
      <TodoTemplate  >
        <TodoInsert insert={insert} />
        <TodoList todos={todos}/>
      </TodoTemplate>
    </div>
  );
};

export default App;

 

여기서 useCallBack()를 사용하는데 이는 필요할 때만 생성할 수 있게 해 준다. 또 useRef()는 지역변수를 만들어줄 수 있는 함수로 사용할 수도 있다.

 

import React, { useState, useCallback, useRef } from 'react';
import './TodoInsert.css'

const TodoInsert = ({insert}) => {

    const [value, setValue] = useState('');
    const input = useRef(null);

    const onChange = useCallback(e => {
        setValue(e.target.value)
    });
    
    const onClick = useCallback(e=>{
        e.preventDefault();
        insert(value);
        setValue('');
        input.current.focus();
    },[insert, value]);

    return (
        <form className="TodoInsert"
            onSubmit={onClick}>
            <input
               placeholder="내용을 입력하세요"
               value={value}
               onChange={onChange}
               ref={input}
            />
            <button>추가</button>
        </form>
    );
};

export default TodoInsert;

 

TodoInsert도 위처럼 변경하면 잘 전달되는 것이 보인다. 또 여기서 사용한 useRef로 추가하면 focus 가 자동으로 input으로 가지는 것을 볼 수 있다.

 

 이제 삭제와 완료를 해본다.

 

//App.js
...


  const remove = useCallback(id => {
    setTodos(todos.filter(todo=>todo.id !== id))
  },[todos]);

  const success = useCallback(id => {
    setTodos(todos.map(todo => todo.id !== id ? todo : {...todo, check: !todo.check})
  )},[todos]);

  return (
    <div>
      <TodoTemplate  >
        <TodoInsert insert={insert} />
        <TodoList todos={todos} remove={remove} success={success}/>
      </TodoTemplate>
    </div>
  );
};

export default App;

 

삭제와 완료 함수를 정의를 하고 이것을 TodoList의 props로 전달해준다.

 

import React from "react";
import "./TodoList.css";
import TodoListItem from "./TodoListItem";

const TodoList = ({ todos, remove, success }) => {
  return (
    <div className="TodoList">
      {todos.map(todo => (
        <TodoListItem
          key={todo.id}
          todo={todo}
          remove={remove}
          success={success}
        />
      ))}
    </div>
  );
};

export default TodoList;

 

다시 TodoListItem에 전달해준다.

 

import React, { useCallback } from "react";
import "./TodoListItem.css";

const TodoListItem = ({ todo, remove, success }) => {
  const { id, contents, check } = todo;
  return (
    <div className="TodoListItem">
      <div className= "complate" onClick={() => success(id)}>
        완료
      </div>
      <div className={check ? "todo success" : "todo" } >{contents}</div>
      <div className="delete" onClick={() => remove(id)}>
        삭제
      </div>
    </div>
  );
};

export default TodoListItem;

 

이렇게 다 구현을 해주면 삭제와 완료가 가능해진다. 이제 시작을 하면 전체적으로 가능해진 것을 볼 수 있다.

 

 

몇 가지 최적화가 남았지만 기본적인 TodoList는 끝났다.

'프로젝트 > Todo' 카테고리의 다른 글

간단한 TodoList만들기 - (1)  (0) 2020.01.10

댓글