[React] 기능 구현_④수정 기능 구현

겨레·2024년 11월 26일

[React] 리액트 스터디

목록 보기
66/95

수정 기능도 방금 만든 삭제 기능과 비슷하다.

✔ ① onToggle이라는 함수를 App에 만들고
✔ ② 해당 함수를 TodoList 컴포넌트에게 props로 넣어준다.
✔ ③ 그다음 TodoList를 통해 TodoListItem까지 전달해 주면됨!


① onToggle 구현하기

✅ 배열 내장 함수 map을 사용해서 특정 id를 가진 객체의 checked 값을 반전시켜 줌.
👉 map을 사용하면 불변성을 유지하면서 특정 배열 원소를 업데이트해야 할 때 짧은 코드로 쉽게 작성할 수 있음!

❓🤔 왜 map이 사용된 걸까?

map 함수
배열을 전체적으로 새로운 형태로 변환해 새로운 배열을 생성해야 할 때 사용한다.


❓🤔 그런데, 지금은 딱 하나의 원소만 수정하는데 왜 map을 사용할까?

onToggle 함수를 보면 삼항 연산자가 사용됨.

todo.id === id ?:

todo.id와 현재 파라미터로 사용된 id 값이 같을 땐, 우리가 정해 준 규칙대로 새로운 객체를 생성함.
id 값이 다를 때는 변화를 주지 않고 처음 받아 왔던 상태 그대로 반환함.

👉 그래서 map을 사용하여 만든 배열에서 변화가 필요한 원소만 업데이트되고, 나머지는 그대로 남아 있게 되는 것!

  • App.jsx
import React, { useState, useRef, useCallback } from 'react';
import TodoTemplate from './components/TodoTemplate';
import TodoInsert from './components/TodoInsert';
import TodoList from './components/TodoList';
import { to } from './../node_modules/sprintf-js/src/sprintf';

const App = () => {
  /* todos 배열 안에 들어 있는 객체 
     => 각 항목의 고유 id, 내용, 완료 여부를 알려 주는 값이 있음.
  */
  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);

  // 추가
  const onInsert = useCallback(
    (text) => {
      const todo = {
        id: nextId.current,
        text,
        checked: false,
      };
      setTodos(todos.concat(todo));
      nextId.current += 1; // nextId 1씩 더하기
    },
    [todos],
  );

  // 삭제
  const onRemove = useCallback(
    (id) => {
      setTodos(todos.filter((todo) => todo.id !== id));
    },
    [todos],
  );

  // 수정
  const onToggle = useCallback((id) => {
    setTodos(
      todos.filter((todo) =>
        todo.id === id ? { ...todo, checked: !todo.checked } : todo,
      ),
    );
  });

  return (
    <TodoTemplate>
      {/* <TodoInsert /> */}
      <TodoInsert onInsert={onInsert} />
      {/* <TodoList /> */}
      {/* todos 배열을 TodoList로 전달 */}
      <TodoList todos={todos} onRemove={onRemove} onToggle={onToggle} />
    </TodoTemplate>
  );
};

export default App;



② 해당 함수를 TodoList 컴포넌트에게 props로 넣어주기

-jsx

import React from 'react';
import './TodoList.scss';
import TodoListItem from './TodoListItem';

const TodoList = ({ todos, onRemove, onToggle }) => {
  return (
    <div className="TodoList">
      {/* todos 배열이 TodoList에 props로 전달되면서 3번 저렇게 작성할 필요가 없어짐!*/}
      {/* 
      <TodoListItem />
      <TodoListItem />
      <TodoListItem /> 
      */}
      {/* 대신에... props로 받아 온 todos 배열을 배열 내장 함수 map을 사용해 TodoListItem으로 이루어진 배열로 변환해서 렌더링!*/}
      {/* map을 사용해 컴포넌트로 변환할 때 => key props를 전달해줘야 함. */}
      {/* todo 데이터는 통째로 props로 전달 => 여러 종류의 값 전달 시, 추후 성능 최적화할 때 편리 */}
      {todos.map((todo) => (
        <TodoListItem todo={todo} key={todo.id} onRemove={onRemove} onToggle={onToggle}/>
      ))}
    </div>
  );
};

export default TodoList;



③ TodoListItem에서 토글 함수 호출하기

  • TodoListItem.jsx
import React from 'react';
import {
  MdCheckBoxOutlineBlank,
  MdRemoveCircleOutline,
  MdCheckBox,
} from 'react-icons/md';
import './TodoListItem.scss';
import cn from 'classnames';

export default function TodoListItem({ todo, onRemove, onToggle }) {
  const { id, text, checked } = todo;

  return (
    <div className="TodoListItem">
      {/* 
      <div className="checkbox">
        <MdCheckBoxOutlineBlank />
        <div className="text">할 일</div>
      </div>
    */}
      <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>
    </div>
  );
}

profile
호떡 신문지에서 개발자로 환생

0개의 댓글