9-8 항목 토글 기능 구현하기

송한솔·2023년 6월 7일
0

ReactStudy

목록 보기
54/54

체크박스를 통해 항목을 체크하는 기능을 구현해 보겠습니다.

이것 또한 onRewrite함수를 App.js에 만들고 TodoList를 통해 TodoListItem에 전달해주세요

  // 항목 토글 기능 구현
  const onToggle = useCallback(
    id => {
      setTodos(
        todos.map(todo => todo.id === id? {...todo, checked: !todo.checked} : todo)
      );
    },
    [todos],
  );

이 함수는 항목의 id를 파라미터로 받아, 해당 항목의 checked 속성을 반대로 변경합니다.

  1. todo.id === id
    현재 반복문(map함수)을 돌며 처리 중인 todo 항목의 id와 함수에 전달된 id(즉, 클릭하여 토글하려는 todo 항목의 id)가 같은지를 비교하는 조건문입니다. 같다면 true를, 아니라면 false를 반환합니다.

  2. { ...todo, checked: !todo.checked }
    이 부분은 JavaScript의 스프레드 연산자와 객체 리터럴을 사용하여, 기존의 todo 객체에 대한 새로운 복사본을 만들고, 그 복사본의 checked 속성 값을 반전시킨 새로운 객체를 생성합니다. { ...todo }는 todo 객체의 모든 속성을 새 객체에 복사하고, checked: !todo.checked는 복사본의 checked 속성 값을 기존 값의 반대로 설정합니다. 결과적으로, 이 코드는 todo 항목의 체크 상태를 토글한 새로운 객체를 반환합니다.

  3. todo가 반환되는 경우는 todo.id === id의 결과가 false일 때입니다. 즉, 현재 반복문을 돌며 처리 중인 todo 항목의 id가 함수에 전달된 id와 다른 경우입니다. 이 경우는 토글하려는 항목이 아니므로, todo 항목을 그대로 반환합니다.


App.js

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

function App() {
  const [todos, setTodos] = useState([
    {
      id: 1,
      text: "리액트 기초 알아보기",
      checked: true,
    },
    {
      id: 2,
      text: "컴포넌트 스타일링해 보기",
      checked: true,
    },
    {
      id: 3,
      text: "일정관리 앱 시작하기",
      checked: false,
    },
  ]);

  /// 고유값으로 사용할 id => ref를 사용하여 변수 담기
  const nextId = useRef(4);
  
  // 항목을 추가할 onIsert 함수 생성
  const onInsert = useCallback(text => {
      const todo = {
        id: nextId.current,
        text,
        checked: false,
      };
      setTodos(todos.concat(todo));
      nextId.current += 1; // nextId 1씩 더하기
    },
    [todos]
  );// 의존성 배열 ▼
  // todos가 변경될 때마다 새로운 함수가 생성됩니다.
  // 따라서, onInsert 함수는 항상 최신의 todos 배열을 참조하게 됩니다.

  // 항목 제거기능 구현
  const onRemove = useCallback(
    id => {
      setTodos(todos.filter(todo => todo.id !== id));
    },
    [todos],
  );

  // 항목 토글 기능 구현
  const onToggle = useCallback(
    id => {
      setTodos(
        todos.map(todo => todo.id === id? {...todo, checked: !todo.checked} : todo)
      );
    },
    [todos],
  );
    


  return (
    <div>
      <TodoTemplate>
        <TodoInsert onInsert={onInsert}/> {
        /* 생성한 onInsert를 TodoInsert의 props로 설정 */}
        <TodoList todos = {todos} onRemove = {onRemove} onToggle={onToggle}/>
      </TodoTemplate>
    </div>
  );
}

export default App;

TodoList.js

import TodoListltem from "./TodoListltem";
import "./TodoList.css";

const TodoList = ({ todos, onRemove, onToggle }) => {
    return (
        <section className="TodoList">
            {todos.map(item => (
                <TodoListltem
                  todo={item}
                  key={item.id}
                  onRemove={onRemove}
                  onToggle={onToggle}
                />
            ))}
        </section>
    );
};

export default TodoList;

TodoListItem.js

import {
    MdCheckBoxOutlineBlank,
    MdCheckBox,
    MdRemoveCircleOutline
} from "react-icons/md";
import "./TodoListItem.css";
import cn from "classnames";

const TodoListltem = ({ todo, onRemove, onToggle }) => {
    const { id, text, checked } = todo;

    return (
        <section className='TodoListItem'>
            <div className={cn("checkbox", { checked })} onClick={() => onToggle(id)}>
                {checked ?<MdCheckBox/>: <MdCheckBoxOutlineBlank/>}
                <div className="text">{text}</div>
            </div>
            <div className="remove" onClick={() => onRemove(id)}>
                <MdRemoveCircleOutline/>
            </div>
        </section>
    );
};

export default TodoListltem;

결과

0개의 댓글