[App 컴포넌트]
import './App.css'
import { useState, useRef } from 'react';
import Editor from './components/Editor'
import Header from './components/Header'
import List from './components/List'
const mockData = [
{
id: 0,
isDone: false,
content: "콩두부 산책하기",
date: new Date().getTime(),
},
{
id: 1,
isDone: false,
content: "명상하기",
date: new Date().getTime(),
},
{
id: 2,
isDone: false,
content: "코딩하기",
date: new Date().getTime(),
},
];
function App() {
const [todos, setTodos] = useState(mockData);
const idRef = useRef(3);
const onCreate = (content) => {
const newItem = {
id: idRef.current++,
content,
isDone: false,
Date: new Date().getTime(),
};
setTodos([newItem, ...todos]);
}
// 인수: todos 배열에서 targetId와 일치하는 id를 갖는 요소의 데이터만 딱 바꾼 새로운 배열
const onUpdate = (targetId) => {
setTodos(todos.map((todo) => todo.id === targetId ? { ...todo, isDone: !todo.isDone } : todo));
};
// 매개변수로 삭제할 아이템의 targetId 받아오기
// 해당 targetId를 갖는 것을 todos State로부터 제거해주면 된다.
const onDelete = (targetId) => {
// 인수: todos 배열에서 targetId와 일치하는 id를 갖는 요소만 삭제한 새로운 배열을 넣는다.
setTodos(todos.filter((todo) => todo.id !== targetId));
// 기존 요소에서 조건을 만족하는 요소만 제외하고 나마지 요소들만 filter
// 모든 todo를 순차적으로 순회를 하면서
// 삼항 연산자로 todo의 id 값이 targetId와 같지 않은 것만 필터링 하도록 만든다.
// 즉, 삭제 되어야 하는 아이템만 제외하고 새로운 배열을 만들어서 인수로 전달
}
return (
<div className="App">
<Header />
<Editor onCreate={onCreate} />
<List todos={todos} onUpdate={onUpdate} onDelete={onDelete} />
</div>
)
}
export default App;
[Header 컴포넌트]
import "./Header.css";
const Header = () => {
return (
<div className='Header'>
<h3>TODAY💛</h3>
<h1>{new Date().toDateString()}</h1>
</div>
);
}
export default Header;
[Editor 컴포넌트]
import "./Editor.css";
import { useState, useRef } from 'react';
const Editor = ({ onCreate }) => {
const [content, setContent] = useState("");
const inputRef = useRef();
const onChangeContent = (e) => {
setContent(e.target.value);
};
const onKeyDown = (e) => {
if (e.keyCode === 13) {
onSubmit();
}
}
const onSubmit = () => {
if (!content) {
inputRef.current.focus();
return
}
onCreate(content);
setContent("");
}
return (
<div className="Editor">
<input
ref={inputRef}
value={content}
onChange={onChangeContent}
onKeyDown={onKeyDown}
placeholder='새로운 Todo를 입력해주세요.'
/>
<button onClick={onSubmit}>추가</button>
</div>
);
}
export default Editor;
[List 컴포넌트]
import { useState } from 'react';
import "./List.css";
import TodoItem from './TodoItem';
const List = ({ todos, onUpdate, onDelete }) => {
const [search, setSearch] = useState("");
const onChangeSearch = (e) => {
setSearch(e.target.value);
}
const getFilteredData = () => {
return search === "" ? todos : todos.filter((todo) => todo.content.toLowerCase().includes(search.toLowerCase()));
};
const filteredTodos = getFilteredData();
return (
<div className='List'>
<h4>Todo List 🏠</h4>
<input value={search} onChange={onChangeSearch} placeholder='검색어를 입력하세요' />
<div className='todos_wrapper'>
{filteredTodos.map((todo) => {
return (
<TodoItem
key={todo.id}
{...todo}
onUpdate={onUpdate}
onDelete={onDelete}
/>
);
})}
</div>
</div>
);
}
export default List;
[TodoItem 컴포넌트]
import "./TodoItem.css";
const TodoItem = ({ id, isDone, content, date, onUpdate, onDelete }) => {
const onChangeCheckbox = () => {
onUpdate(id);
};
const onClickDeleteButton = () => {
onDelete(id);
}
return (
<div className='TodoItem'>
<input onChange={onChangeCheckbox} checked={isDone} type='checkbox' />
<div className='content'>{content}</div>
<div className='date'>{new Date().toLocaleDateString()}</div>
<button onClick={onClickDeleteButton}>삭제</button>
</div>
)
}
export default TodoItem;
'기술 > React' 카테고리의 다른 글
| Vite (0) | 2024.03.28 |
|---|---|
| [React] 프로젝트 ▶ TodoList ▶ 요구사항 분석, 컴포넌트 분리, UI 구현 (0) | 2024.03.21 |
| [React] 이벤트 처리하기 (0) | 2024.02.27 |
| [React] 컴포넌트 (0) | 2024.02.27 |
| [React] 리액트의 데이터 흐름 (0) | 2024.02.27 |