npx create-react-app 프로젝트명
html 구조 잡기
더미 데이터 만들어서 최종적으로 만들려는 ui 기본 틀 구현
데이터의 상태(todos)를 관리해야하기 때문에 useState()
사용
(여러 개의 todo를 담기 위해 배열형태 [{}, {}, {}, ...])
각 todo에는 id, title, body, isDone이 들어감
const [todos, setTodos] = useState([])
todos.map으로 todo를 화면에 그려줌
todo.isDone 상태에 따라 조건부 렌더링
<section>
<h2>Working... 🔥</h2>
{todos.map((todo) => {
if (!todo.isDone) {
return (
<div key={todo.id}>
<h3>{todo.title}</h3>
<p>{todo.body}</p>
<button>삭제하기</button>
<button>완료</button>
</div>
);
}
})}
</section>
<section>
<h2>Done..! 🎉</h2>
{todos.map((todo) => {
if (todo.isDone) {
return (
<div key={todo.id}>
<h3>{todo.title}</h3>
<p>{todo.body}</p>
<button>삭제하기</button>
<button>완료</button>
</div>
);
}
})}
</section>
사용자가 입력한 input값을 데이터로 관리(inputs)하기 위해 useState()
사용
input 여러 개를 함께 관리하기 위해 name을 붙이고 onChange 함수를 연결
const [inputs, setInputs] = useState({
title: '',
body: '',
});
// e.target.name 이 inputs의 key 값으로 사용 => [] 표기법 사용
const inputChangeHandler = (e) => {
setInputs({
...inputs,
[e.target.name]: e.target.value,
});
};
<input
type='text'
name='title'
value={inputs.title}
onChange={inputChangeHandler}
/>
form 에 onsubmit 함수를 연결
브라우저 새로고침 막아주기 (e.preventDefault())
새로운 todo 객체(newTodo) 만들어서 setTodos()로 todos 업데이트 => 불변성
추가 후 input 값 비워주기
const submitHandler = (e) => {
e.preventDefault();
const newTodo = {
id: todos.length,
title: inputs.title,
body: inputs.body,
isDone: false,
};
setTodos([...todos, newTodo]);
setInputs({
title: '',
body: '',
});
};
삭제버튼에 onClick 함수 연결
id를 받아와서 클릭된 todo의 id와 받아온 id가 일치하지 않는 것만 filter
const deleteTodo = (id) => {
setTodos(todos.filter((todo) => todo.id !== id));
};
완료버튼에 onClick 함수 연결
id를 받아와서 클릭된 todo의 id와 받아온 id가 일치하면
todo.isDone의 상태를 바꾼 다음 return
const toggleTodo = (id) => {
setTodos(
todos.map((todo) => {
if (todo.id === id) {
todo.isDone = !todo.isDone;
}
return todo;
})
);
};
💥 todo를 추가하는 과정에서 id값을 todos.length
로 줬는데
삭제하고 새로운 todo를 추가할 때 id가 중복되는 문제가 생김
💡 중복되지 않는 고유한 id 필요 => uuid 라이브러리
(여러 버전이 있는데 버전이 높아질 수록 견고한 고유 값을 제공함)
설치
npm install uuid
/ yarn add uuid
사용법
import {v4 as uuidv4} from 'uuid'
const id = uuidv4()
=> import 후 사용하고자 하는 곳에서 함수처럼 사용
form 부분을 컴포넌트로 분리
todo가 렌더링 되는 부분을 크게 분리하고 그 안에 TodoItem을 또 분리
✔ 진행중 / 완료 section에 중복되는 코드가 많아서 컴포넌트로 분리 시도
💥1. 서로 title이 다르고 isDone 상태에 따라 분리해서 보여줘야 함
💥2. 컴포넌트안에 title을 그대로 가져오려고 했지만 데이터가 없으면 title 마저 보이지 않음
💡 title과 isDone 이라는 props를 추가하고 isDone이 true/false일 때를 나누어
todos를 가공해 나온 결과인 filteredTodos를 map으로 돌면서 렌더링
// app.js
<TodoList
todos={todos}
deleteTodo={deleteTodo}
toggleTodo={toggleTodo}
title='Working... 🔥'
isDone={false}
/>
<TodoList
todos={todos}
deleteTodo={deleteTodo}
toggleTodo={toggleTodo}
title='Done...! 🎉'
isDone={true}
/>
// todoList.jsx
const TodoList = ({ todos, deleteTodo, toggleTodo, title, isDone }) => {
const filteredTodos = isDone
? todos.filter((todo) => todo.isDone)
: todos.filter((todo) => !todo.isDone);
return (
<section>
<h2>{title}</h2>
{filteredTodos.map((todo) => (
<TodoItem
key={todo.id}
todo={todo}
deleteTodo={deleteTodo}
toggleTodo={toggleTodo}
/>
))}
</section>
);
};
각각의 todo 를 컴포넌트로 분리
요구사항에 있는 최대, 최소 넓이 적용
추후 스타일링 하기 쉽도록 (구역을 볼 수 있게) 색상만 일단 넣음 (디자인테러😫)