Todo 예제

2022. 11. 10. 23:22React/React Hook

반응형

예제는 아주 간단한 예제이지만 처음에 React를 접하고 나서 잘 이해가 가지 않았지만 몇번을 보고 나서는 이해 하게 되었다. 특히 앞선 클로저를 이해하고 나서는 왜 변경함수를 통하여 현재 상태값을 변경하는지도 이해하기 쉬웠던거 같다.

 

비록 간단한 예제 이지만 처음으로 React를 접하는 분들에게는 꼭 useState를 잘 이해하기를 바랍니다.

 

전체적인 컴포넌트 구조는 아래와 같다.

Todo 컴포넌트 구조

위의 화면은 Todo 예제 전체 컴포넌트 구조 이다. 부모 컴포넌트는 Todo 이고 자식 컴포넌트는 TodoForm, TodoList 로 구성 된다.

 

[Todo.jsx]

import React, { useState } from "react";
import TodoForm from "./TodoForm.";
import TodoList from "./TodoList";

const Todo = () => {
  // Todo 목록 설정 
  const [userTodos, setUserTodos ] = useState([]);

  // ① Todo 항목 추가
  const addTodoHandler = (todo) => {
    setUserTodos(prevTodos => [
      ...prevTodos,
      { id: Math.random().toString(), ...todo},
    ]);    
  }

  // ② Todo 항목 삭제
  const removeTodoHandler = todoId => {
    setUserTodos(prevTodos =>
      prevTodos.filter(todo => todo.id !== todoId)
    );
  };

  return (
    <div className="h-100 w-full flex items-center justify-center">
      <div className="p-4 m-4 w-full lg:w-3/4 lg:max-w-3xl">
        <TodoForm onAddTodo={addTodoHandler} />
        <section>
          <TodoList todos={userTodos} onRemoveItem={removeTodoHandler} />
        </section>
      </div>
    </div>
  );
};

export default Todo;

① addToHandler(Todo 항목 추가)

setUserTodos 변경함수 파라미터에 [가장최근상태값,사용자가입력한값] 값으로 목록값을 갱신한다.

 

② removeTodoHandler (Todo 항목 삭제)

setUserTodos 변경함수에서 현재상태값에서 TodoList에서 전달받은 id값을 제외한 값으로 목록값을 갱신한다.

 

Todo 등록하기

입력한 내용은 아래 그림과 같이 Todo(부모) 컴포넌트에서 props 속성으로 onAddTodo 를 전달하게 되고 ① TodoForm(자식) 컴포넌트에서는 아래 그림에서 보듯이 props.onAddTodo(전달값/객체) 를 호출 하게 되고 ② Todo(부모) 컴포넌트에서는 addToHandler 함수를 호출 하여 입력 값을 처리 한다.

 

[TodoForm.jsx]

import React, { useState } from "react";

const TodoForm = (props) => {  
  const [ enteredTodo, setEnteredTodo ] = useState('');

  const submitHandler = (event) => {
    event.preventDefault();
    props.onAddTodo({content: enteredTodo});
    setEnteredTodo('');
  }

  return (
    <>
      <div>
        <h1 className="inline-block text-2xl sm:text-3xl font-extrabold text-slate-900 tracking-tight dark:text-slate-200">
          Todo List
        </h1>
      </div>
      <form onSubmit={submitHandler}>
        <div className="flex mt-6">
          <input
            type="text"
            className="shadow-md shadow-blue-200/40 md:shadow-indigo-200/40 border rounded w-full py-2 px-3 mr-2"
            placeholder="Add Todo"
            id="todo"
            value={enteredTodo}
            onChange={event => {
              setEnteredTodo(event.target.value);
            }}
          />
          <button className="bg-rose-500 hover:bg-rose-700 text-white font-bold py-2 px-4 border border-rose-700 rounded">
            ADD
          </button>
        </div>
      </form>
    </>
  );
};

export default TodoForm;

위의 코드에서 사용자가 입력한 값이 어떻게 Todo(부모) 컴포넌트에게 전달되는지 보자

  1. input 태그에서 사용자가 글을 입력 할때마다 onChange 이벤트 호출
  2. onChage 이벤트 호출 시 setEnteredTodo 상태변경함수를 호출 하여서 사용자가 입력한 내용을 현재상태 값으로 저장한다.
  3. Add 버튼 클릭 시 submitHandler 함수를 호출한다.
  4. submitHandler 함수에서는 props.onAddTodo({입력값}) 통하여 Todo(부모) 컴포넌의 addToHandler 함수를 통하여 입력 값을 처리한다.

 

Todo 목록

Todo(부모) 컴포넌트에서 전달받은 Todo 목록 데이터를 Redering 처리한다.

 

[TodoList.jsx]

import React, { useState } from "react";

import ClearIcon from "@mui/icons-material/Clear";
import DoneIcon from "@mui/icons-material/Done";

const TodoList = (props) => {

  const [ taskCss, setTaskCss ] = useState('inline-block mt-1 text-md text-slate-900');
  const [ taskDone, setTaskDone ] = useState(false);
  
  // Done event 처리 함수
  const doneHandler = () => {
    setTaskDone(!taskDone);

    if (taskDone) {
      setTaskCss('mt-1 text-md text-rose-900 line-through');
    }
    else {
      setTaskCss('mt-1 text-md text-slate-900');
    }
  };

  return (
    <ul className="list-none mt-3">
      {props.todos.map(todo => (
        <li
          key={todo.id}
          className="flex items-center justify-between px-2 py-3 border-b"
        >
          <div>
            <p className={taskCss}>{todo.content}</p>
          </div>
          <div>
            <ClearIcon
              style={{ color: "red" }}
              onClick={props.onRemoveItem.bind(this, todo.id)}
              className="cursor-pointer"
            /> // ① Todo내용 삭제
            <DoneIcon
              style={{ color: "darkgreen" }}
              onClick={doneHandler}
              className="cursor-pointer"
            /> // ② Todo내용 완료 처리 
          </div>
        </li>
      ))}
    </ul>
  );
};

export default TodoList;

① Todo내용 삭제

  1. 삭제(ClearIcon) 클릭시 props.onRemoveItem(현재선택된내용의ID) 통하여 Todo(부모) 컴포넌트의 removeTodoHandler 함수를 호출 하여 삭제 처리 한다.

② Todo내용 완료 처리

  1. 완료(DoneIcon) 클릭시 내부의 doneHanler 함수를 호출 하여서 현재 완료여부 값을 setTaskDone 함수를 통하여 변경 한다.
  2. taskDone 이 true 이면 입력내용에 취소선을 넣어서 완료 표시를 하기위한 css 속성을 설정 하고 그 반대인 경우는 취소선을 해제하는 css 속성을 설정한다.

 

Wrap up

  • useState 를 통하여 값을 변경하는 경우 변경 함수를 통하여서 값을 변경한다.
  • 부모-자식 간의 값 전달은 props를 통하여 할 수 있다. 물론 props 외에도 다른 방법이 있지만 본예제에서는 props를 통한 값의 전달 및 목록 갱신에 대해서 알아 보았다.
  •  

예제소스 및 프로젝트 생성 및 라이브러리 설치 방법

https://github.com/roopy1210/react-project-react-hook-usestate-example

 

GitHub - roopy1210/react-project-react-hook-usestate-example

Contribute to roopy1210/react-project-react-hook-usestate-example development by creating an account on GitHub.

github.com

 

반응형

'React > React Hook' 카테고리의 다른 글

useState 와 클로저  (0) 2022.11.10