[Type Script] Todo 앱 연습: Todo 클릭하여 삭제하기

summereuna🐥·2023년 8월 22일
0

TypeScript

목록 보기
4/13

Todo를 클릭하면 삭제되게 해보자.
아이디로 검증하면 된다.

1. Todo.tsx

import classes from "./Todo.module.css";

const Todo: React.FC<{
  text: string;
  onRemoveTodo: () => void; //🔥props으로 내려받은 함수에 대해 타입 명시
}> = (props) => {

  return (
    <li
      onClick={props.onRemoveTodo}
      className={classes.item}
    >
      {props.text}
    </li>
  );
};

export default Todo;

여기에 왜 id 값은 없냐! 라고 묻는다면 코드 최대한 줄일 수 있는 방향으로 생각했을 때, <Todo />컴포넌트의 상위 컴포넌트인 <Todos /> 컴포넌트에서 onRemoveTodo()함수에 bind() 메서드를 사용하여 id 값을 인자로 넣어 줄 수 있기 때문에 여기서 id 값을 또 props으로 내려 받거나 useRef()등으로 잡아올 필요가 없어진다.

그렇다면 <Todos /> 컴포넌트를 한 번 보자.

2. Todos.tsx

import React from "react";
import Todo from "./Todo";
import classes from "./Todos.module.css";

import TodoClass from "../models/todo";

type Props = {
  items: TodoClass[]; //items은 Todo 객체로 채워진 배열
  children?: React.ReactNode; //옵셔널
  onRemoveTodo: (id: string) => void; //🔥props으로 내려받은 함수에 대해 타입 명시
};

const Todos: React.FC<Props> = (props) => {
  //console.log("✅", props.onRemoveTodo);
  //console.log("✅✅", props.onRemoveTodo.bind(null));

  return (
    <ul className={classes.todos}>
      {props.items.map((item) => (
        <Todo
          key={item.id}
          text={item.text}
          // id={item.id} //❗️bind 덕분에 굳이 id 하위 컴포넌트로 안 내려줘도 됨
          onRemoveTodo={props.onRemoveTodo.bind(null, item.id)}
        />
        //따라서 items의 각요소의 id, text 프로퍼티를 사용할 수 있다.
      ))}
    </ul>
  );
};
export default Todos;

props.onRemoveTodo.bind(null, item.id)

  1. bind() 메서드의 첫 번째 인자
    onRemoveTodo()를 통해 호출될 함수 안에서 무엇을 가르킬지 this를 지정해 줄 수 있다.
    여기선 따로 지정할 필요 없으니 null
  • console.log("✅", props.onRemoveTodo);
    console.log("✅✅", props.onRemoveTodo.bind(null));

    onRemoveTodo()함수에 bind() 메서드 호출 시, this를 null로 지정하면 같은 함수를 가리킴(당연함..^^)
  1. bind() 메서드의 두 번째 인자
    두 번째 인수에 넣는 값은 onRemoveTodo()가 매개변수로 받을 수 있게되므로 item.id 값 넣어주기

bind()를 활용하여 함수에 인자를 넣어줄 수 있으므로, 굳이 하위 컴포넌트 까지 내려가지 않고서도 중간에 있는 컴포넌트에서 bind로 item.id값을 줄 수 있기 때문에 코드를 좀 덜 쓸 수 있다.

3. App.tsx

import { useState } from "react";
import "./App.css";
import NewTodo from "./components/NewTodo";
import Todos from "./components/Todos";
import TodoClass from "./models/todo";

function App() {
  const [todos, setTodos] = useState<TodoClass[]>([]);

  const addTodoHandler = (newTodoText: string) => {
    const newTodo = new TodoClass(newTodoText);
    setTodos((prevTodos) => {
      return prevTodos.concat(newTodo);
    });
  };

  // Todo 제거하는 핸들러
  const removeTodoHandler = (clickedTodoId: string) => {
    setTodos((prevTodos) => {
      //배열의 아이템들 다 돌려서 id 값이 removeTodoHandler가 받은 인자인 clickedTodoId값과 같지 않은 것만 모아 새로운 배열로 반환하기
      return prevTodos.filter((todo) => todo.id !== clickedTodoId);
    });
  };

  return (
    <div>
      <NewTodo onAddTodo={addTodoHandler} />
      <Todos items={todos} onRemoveTodo={removeTodoHandler} />
    </div>
  );
}

export default App;
profile
Always have hope🍀 & constant passion🔥

0개의 댓글