[React] todo-list (day15)

DanStudio!·2022년 8월 15일
0

React

목록 보기
4/7
post-thumbnail

이전 포스팅 [React] todo-list (day13)에 이어
드디어 Todo List를 완성하게 되었다.

첫 리엑트 프로젝트이기 때문에 처음에 많이 헤맸지만 여러 블로그참고 및 React기술매니져님께 질문을 통해 방법을 찾으며 점점 틀을 잡아갈 수 있었다.

위의 사진과 같이 컴포넌트를 배치하였다.

Todo.jsx

import React from "react";
import "./style.css";
const Todo = ({ todo, remove, onToggle }) => {
  const { id, title, body } = todo;
  return (
    <div className="container">
      <div className="todos">
        <h3 className="todoTitle">{title}</h3>
        <h4 className="todoContents">{body}</h4>
        <div className="todoButtons">
          {todo.isDone === false ? (
            <button className="todoButton" onClick={() => onToggle(id)}>
              Nailed it!</button>
          ) : (
            <button className="todoButton" onClick={() => onToggle(id)}>
              Cancel ⛔️
            </button>
          )}
          <button className="todoButton" onClick={() => remove(id)}>
            remove ❌
          </button>
        </div>
      </div>
    </div>
  );
};

export default Todo;

Todo는 isDone의 값이 true일 때와 false일 때로 나누어야 했기 때문에 Working과 Done 두 컴포넌트로 분리를 하였다.

Working.jsx

import React from "react";
import Todo from "../todo/Todo";
import "./style.css";

const Working = ({todos, remove, onToggle}) => {
  return (
    <div className="working">
      {todos
        .filter((todo) => todo.isDone === false)
        .map((todo, idx) => (
          <Todo todo={todo} key={idx} remove={remove} onToggle={onToggle}/>
        ))}
    </div>
  );
};

export default Working;

Done.jsx

import React from "react";
import Todo from "../todo/Todo";
import "./style.css";

const Done = ({todos, remove, onToggle}) => {
  return (
    <div className="done">
      {todos
        .filter((todo) => todo.isDone === true)
        .map((todo, idx) => (
          <Todo todo={todo} key={idx} remove={remove} onToggle={onToggle}/>
        ))}
    </div>
  );
};

export default Done;

List.jsx

import React from "react";
import Done from "./Done";
import Working from "./Working";
import "./style.css";

const List = ({todos, remove, onToggle}) => {
  //component별로 진행중, 진행완료로 나눈다.
  // working -> todo components 호출 (false)
  // done -> todo components 호출 (true)
 
  
  return (
    <div className="lists">
      <h2 className="status">Work in progress . . 🫡</h2>
      <Working todos={todos} remove={remove} onToggle={onToggle}/>
      <h2 className="status">Done ! 😎</h2>
      <Done todos={todos} remove={remove} onToggle={onToggle}/>
    </div>
  );
};

export default List;

Header.jsx

import React from 'react';
import './style.css';
import icon from './logo192.png';
const Header = () => {
  return (
    <div className='header'>
      <a href='/'>My Todo List</a>
      <p>React <img style={{height:'25px', transform:'translateY(2px)'}} src={icon} alt="Icon"/></p>
    </div>
  );
};

export default Header;

Form.jsx

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

const Form = ({title, body, onChangeHandler, onSubmitHandler}) => {
  return (
      <div className='formDiv'>
        <form className='todoInput'>
        <label>Title :</label>
        <input name='title' type='text' value={title} onChange={onChangeHandler}/>
        <label>Contents :</label>
        <input name='body' type='text' value={body} onChange={onChangeHandler}/>
        <button id="submit" type='submit' onClick={onSubmitHandler}>Submit</button>
        </form>
    </div>
  );
};

export default Form;

Layout.jsx

import React, { useState } from "react";
import Form from "../form/Form";
import List from "../list/List";
import "./style.css";
const Layout = () => {
  const [input, setInput] = useState({
    title: "",
    body: "",
  });
  const { title, body } = input;

  const onChangeHandler = (e) => {
    const { value, name } = e.target;
    setInput({
      ...input,
      [name]: value,
    });
  };
  const onSubmitHandler = (e) => {
    e.preventDefault();
    if(!input.title||!input.body) return;
    const num = todos.length;
    const todo = {
      id: num + 1,
      title,
      body,
      isDone: false,
    };
    //배열 항목 추가하기
    setTodos([...todos, todo]);
    // setTodos(todos.concat(todo)) concat() 메서드는 인자로 주어진 배열이나 값들을 기존 배열에 합쳐서 새 배열을 반환합니다.
    setInput({
      title: "",
      body: "",
    });
  };
  const [todos, setTodos] = useState([
    {
      id: 1,
      title: "study React",
      body: "Finish todo list",
      isDone: false,
    },
    {
      id: 2,
      title: "wake up Early",
      body: "to study",
      isDone: true,
    },
  ]);
  const remove = (id) => {
    setTodos(todos.filter((todo) => todo.id !== id));
  };
  const onToggle = (id) => {
    //todo.id가 파라미터로 일치하지 않는 원소만 추출해서 새로운 배열을 만듬
    // = todo.id가 id인 것을 제거함
    setTodos(todos.map(
      todo => todo.id === id 
      ? {...todo, isDone: !todo.isDone} : todo
    ));
  };

  return (
    <div className="layOut">
      <Form
        title={title}
        body={body}
        onChangeHandler={onChangeHandler}
        onSubmitHandler={onSubmitHandler}
      />
      <List todos={todos} remove={remove} onToggle={onToggle} />
    </div>
  );
};

export default Layout;

TodoList.jsx

import React from 'react';
import Layout from '../components/layout/Layout';
import Header from '../components/header/Header';

const TodoList = () => {
  return (
    <div>
      <Header/>
      <Layout/>
    </div>
  );
};

export default TodoList;

처음에 Form에서 입력을 받아 부모 component인 Layout으로 Data를 전달하고 자녀 컴포넌트인 List로 뿌려주기 위해 노력하였으나 jsx 문법이 익숙지 않아 헤매던 중 가장 상위 component에서 모든 함수를 작성하는 방법이 더 편할 것 같다는 생각을 하게 되었고 그 이후로는 순조롭게 진행이 된 것 같다.
또 한 가지 쉽지 않았던 부분은 Input이 두 개라는 점이었다.
하지만 useState({title:'', body:''})를 통해 동시에 값을 전달받을 수 있는 방법을 터득하고 나니 크게 어렵지 않았던 것 같다.

깃허브

profile
항해를 시작한 FE 지망생입니다 :)

0개의 댓글