todolist를 여러번 만들었지만, 이번 연휴가 길다보니까 뭔가 복잡한 건 하고 싶지 않고, next js 강의 듣다가 리액트 복습할 겸 다시 만들어 봄
npm create vite@latest
npm install
react + vite
npm run dev
svg파일
을 삭제함5173
임flex-direction: column
을 주면 객체의 아래에 위치함{new Date().toDateString()}
를 통해 오늘(현재)날짜를 받아옴input
창과 button
으로 구성h4
태그로 '오늘의 할 일' 제목 만들고input
창 만들기TodoItem
컴포넌트 생성)TodoItem
컴포넌트 안에는 체크박스, 내용, 버튼 한 세트로 구성TodoEditor
컴포넌트에서 create해서 추가하면TodoItem
에서 read, update, delete를 함App
컴포넌트에 상태관리를 해야 함
import { useRef, useState } from "react";
import "./App.css";
import Header from "./components/Header";
import TodoEditor from "./components/TodoEditor";
import TodoList from "./components/TodoList";
const mockDate = [
{
id: 0,
isDone: true,
content: "공부하기",
createdDate: new Date().getTime(),
},
{
id: 1,
isDone: true,
content: "다영이 괴롭히기",
createdDate: new Date().getTime(),
},
{
id: 2,
isDone: true,
content: "다영이 놀리기",
createdDate: new Date().getTime(),
},
];
function App() {
// 1. todolist를 위한 상태관리 useState hook
const [todos, setTodos] = useState(mockDate);
// 3. id 값을 고유값으로 증가하게 하기 위함
const idRef = useRef(3);
// 2. 생성되는 데이터 값, mock데이터의 프로퍼티와 동일
const onCreate = (content) => {
const newTodo = {
id: idRef.current++,
isDone: false,
content,
createdDate: new Date().getTime(),
};
// 2-1. setTodos로 todolist의 현재 상태로 만들기
// newTodo(새로추가) + 기존에 있던 todos로 배열로 보관
setTodos([newTodo, ...todos]);
};
return (
<div className="App">
<Header />
{/* 4. props로 넘겨주기 */}
<TodoEditor onCreate={onCreate} />
<TodoList />
</div>
);
}
export default App;
import { useState } from "react";
import "./TodoEditor.css";
// 5. props로 받아오기
const TodoEditor = ({ onCreate }) => {
// 6. 입력하는 content의 상태관리를 위한 useState
const [content, setContent] = useState("");
const onChangeContent = (e) => {
setContent(e.target.value);
};
const onClick = () => {
onCreate(content);
};
return (
<div className="TodoEditor">
{/* 7. value값 : input창에 입력하는 값 */}
{/* 8. onChange를 이용해서 입력 value값을 새로운 setContent 값으로 전달 */}
<input
value={content}
onChange={onChangeContent}
placeholder="추가할 할 일"
/>
{/* 9. 추가 버튼을 누르면 새로 입력받아서 onChange로 넘긴 value값을 onCreate로 넘김 */}
<button onClick={onClick}>추가</button>
</div>
);
};
export default TodoEditor;
const TodoEditor = () => {
const inputRef = useRef();
const onClick = () => {
//value(content)에 아무것도 입력하지 않으면, 현재 포커스를 current창에 둠
if (content === "") {
inputRef.current.focus();
return;
}
onCreate(content);
};
return (
<div className="TodoEditor">
<input
ref={inputRef}
value={content}
onChange={onChangeContent}
placeholder="추가할 할 일"
/>
<button onClick={onClick}>추가</button>
</div>
);
}
useRef
가 뭐지?
1. useState 같은 저장공간
useState와 차이점? useState는 state가 변화하면 렌더링이 발생하고, 컴포넌트 내부 변수들이 초기화 됨. 하지만 useRef는 Ref가 변화하더라도 렌더링이 되지 않고 변수들의 값이 그대로 유지됨. 따라서 state의 변화로 렌더되더라도 Ref의 값은 유지됨
2. Document.querySelector같은 역할
input창에 focus()를 하듯이 DOM 요소에 접근이 가능
const onClick = () => {
if (content === "") {
inputRef.current.focus();
return;
}
onCreate(content);
setContent("")
};
const onKeyDown = (e) => {
if (e.keyCode === 13) {
onClick();
}
<input
ref={inputRef}
value={content}
onChange={onChangeContent}
onKeyDown={onKeyDown}
placeholder="추가할 할 일"
/>
{todos.map((todo) => (
<div>{todo.content}</div>
))}
<div className="todos_wrapper">
{todos.map((todo) => (
<TodoItem {...todo} />
))}
</div>
...todo
로 넘겨줌const TodoItem = ({ id, isDone, createdDate, content }) => {
return (
<div className="TodoItem">
<input className="checkbox_col" type="checkbox" checked={isDone} />
<div className="content">{content}</div>
<div className="date">{createdDate}</div>
<button>삭제</button>
</div>
);
};
const [search, setSearch] = useState();
const onChangeSearch = (e) => {
setSearch(e.target.value);
};
const filterTodos = () => {
if (search === "") {
return todos;
}
return todos.filter((todo) =>
todo.content.toLowerCase().includes(search.toLowerCase())
);
};
const onUpdate = (targetId) => {
setTodos(
todos.map((todo) => {
if (todo.id === targetId) {
return {
...todo,
isDone: !todo.isDone,
};
} else {
return todo;
}
})
);
};
const onChangeCheckbox = () => {
onUpdate(id);
};
<input
onChange={onChangeCheckbox}
className="checkbox_col"
type="checkbox"
checked={isDone}
/>
const onDelete = (targetId) => {
setTodos(todos.filter((todo) => todo.id !== targetId));
};
<TodoList todos={todos} onUpdate={onUpdate} onDelete={onDelete} />
<div className="todos_wrapper">
{filterTodos().map((todo) => (
<TodoItem
key={todo.id}
{...todo}
onUpdate={onUpdate}
onDelete={onDelete}
/>
))}
</div>
const onClickDeleteButton = () => {
onDelete(id);
};
<button onClick={onClickDeleteButton}>삭제</button>