리액트 컴포넌트에서 배열의 불변성을 지키면서 배열 원소를 제거해야 할 경우에는 배열 내장 함수인 filter를 사용하면 매우 간편하게 가능하다.
📍 배열 내장 함수 filter
filter 함수는 기존의 배열은 그대로 둔 상태에서 특정 조건을 만족하는 원소들만 따로 추출해 새로운 배열을 만들어 준다.
👉 filter 함수에는 조건을 확인해 주는 함수를 파라미터로 넣어 줘야함.
👉 파라미터로 넣는 함수는 true 혹은 false 값을 반환해야 함.
👉 이때, true를 반환하는 경우만 새로운 배열에 포함됨.
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const biggerThanFive = array.filter(number => number > 5);
// 결과: [6, 7, 8, 9, 10]
filter 함수를 사용해 onRemove 함수를 작성해 보자!
✔ onRemove 함수는 App 컴포넌트에 id를 파라미터로 받아 와서 같은 id를 가진 항목을 todos 배열에서 지우는 함수임!
✔ 그리고 나서 TodoList의 props로 설정해준다.
import React, { useState, useRef, useCallback } from 'react';
import TodoTemplate from './components/TodoTemplate';
import TodoInsert from './components/TodoInsert';
import TodoList from './components/TodoList';
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],
);
return (
<TodoTemplate>
{/* <TodoInsert /> */}
<TodoInsert onInsert={onInsert} />
{/* <TodoList /> */}
{/* todos 배열을 TodoList로 전달 */}
<TodoList todos={todos} onRemove={onRemove} />
</TodoTemplate>
);
};
export default App;
TodoListItem에서 방금 만든 onRemove 함수를 사용하려면...
✔ ① 먼저 TodoList 컴포넌트를 거쳐야한다.
✔ ② props로 받아 온 onRemove 함수를 TodoListItem에 그대로 전달해 주자!
① TodoList 컴포넌트 거치기
import React from 'react';
import './TodoList.scss';
import TodoListItem from './TodoListItem';
const TodoList = ({ todos, onRemove }) => {
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} />
))}
</div>
);
};
export default TodoList;
② 삭제 버튼을 누르면 TodoListItem에서 onRemove 함수에 현재 자신이 가진 id를 넣어 삭제 함수를 호출하도록 설정
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 }) {
const { id, text, checked } = todo;
return (
<div className="TodoListItem">
{/*
<div className="checkbox">
<MdCheckBoxOutlineBlank />
<div className="text">할 일</div>
</div>
*/}
<div className={cn('checkbox', { checked })}>
{checked ? <MdCheckBox /> : <MdCheckBoxOutlineBlank />}
<div className="text">{text}</div>
</div>
<div className="remove" onClick={() => onRemove(id)}>
<MdRemoveCircleOutline />
</div>
</div>
);
}


