App.js
import React, { useCallback, useRef, useState } from 'react';
import TodoInsert from './components/TodoInsert';
import TodoList from './components/TodoList';
import TodoTemplate from './components/TodoTemplate';
function App() {
const [todos, setTodos] = useState([
{
id: 1,
text: '리액트의 기초 알아보기',
checked: true,
},
{
id: 2,
text: '컴포넌트 스타일링 해보기',
checked: true,
},
{
id: 3,
text: '일정 관리 앱 만들기',
checked: false,
},
]);
const nextId = useRef(4);
const onInsert = useCallback(text => {
const todo = {
id: nextId.current,
text,
checked: false,
};
setTodos(todos.concat(todo));
nextId.current++;
}, [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: true} : todo
))
}, [todos]);
return (
<>
<TodoTemplate>
<TodoInsert onInsert={onInsert} />
<TodoList
todos={todos}
onRemove={onRemove}
onToggle={onToggle}
/>
</TodoTemplate>
</>
);
}
export default App;
TodoList.js
import './TodoList.scss';
import TodoListItem from './TodoListItem';
function TodoList({todos, onRemove, onToggle}) {
return (
<div className='TodoList'>
{todos.map(todo => (
<TodoListItem
todo={todo}
key={todo.id}
onRemove={onRemove}
onToggle={onToggle}
/>
))}
</div>
)
}
export default TodoList;
TodoListItem.js
import {
MdCheckBoxOutlineBlank,
MdRemoveCircleOutline,
MdCheckBox
} from 'react-icons/md';
import cn from 'classnames';
import './TodoListItem.scss';
function TodoListItem({todo, onRemove, onToggle}) {
const {id, text, checked} = todo;
return (
<div 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>
</div>
)
}
export default TodoListItem
onToggle 함수로 checked: true 변경
- App.js에서 id와 일치하는 todo를 찾아 {...todo, checked: true} 변경
- 일치하지 않는 todo는 그대로 두기