<h1>Todo Application</h1>
아래에 할 일의 개수를 표현해보자.
App.js
App.js에 Header 컴포넌트를 추가해주고, props로 todos를 전달해준다.
// App.js
. . .
import Header from './components/Header.jsx';
. . .
return(
<>
<h1>Todo Application</h1>
<Header todos={todos} />
<form action="">
<input type="text" name="" onChange={changeInputData}/>
<button onClick={addTodo}>ADD</button>
</form>
<List todos={todos} loading={loading}/>
</>
);
}
export default App;
Header.jsx
components 폴더 안에 Header.jsx 파일을 생성해준다.
// Header.jsx
import React from 'react';
import './Header.css';
function Header({todos}) {
// 미완료 상태(done: false)인 todo들의 배열
const undoneTasks = todos.filter(todo => todo.done === false);
return(
<div className='countInfo'>{`남은 할 일 : ${undoneTasks.length}`}</div>
);
}
export default Header;
현재 initialTodoData.js의 Todo들 중 완료상태done: true
는 3개, 미완료 상태done: false
는 4개이다.
따라서 우리가 확인할 수 있는 결과는 "남은 할 일: 4"이다.
TodoList 목록 중 특정 할 일을 클릭했을 때 완료/미완료 상태 표현을 할 수 있도록 처리해보자.
List.jsx
소스코드의 <li key={todo.todoCode}>{todo.title}</li>
부분을 Item 컴포넌트에 key값과 todos를 전달하는 형식으로 수정한다.
// List.jsx
import React from 'react';
import Item from './Item.jsx';
function List({todos, loading}) {
let todoList = <div>Loading...</div>;
if(!loading) todoList = todos.map(todo => <Item key={todo.todoCode} todo={todo} />);
return(
<ul>
{todoList}
</ul>
);
}
export default List;
Item.jsx
Item.jsx 폴더를 생성하고,
// Item.jsx
import React from 'react';
function Item({todo}) {
// toggleDone : 할 일의 완료/미완료 상태를 표현하는 함수
const toggleDone = () => {
}
return(
<li data-id={todo.todoCode} onClick={toggleDone}>{todo.title}</li>
);
}
export default Item;
App.js
할 일의 Done 상태 값을 바꾸는 함수 changeTodoDone
를 작성한다.
여기서 Done이 true이면 완료상태, false이면 미완료 상태를 의미한다.
그리고 List 컴포넌트와 LIst 컴포넌트 안의 Item 컴포넌트에 changeTodoDone={changeTodoDone}
props를 전달해주는 처리를 한다.
// App.js
import React, { useEffect, useState } from 'react';
import './App.css';
// Custom Hook
import useFetch from './useFetch.js';
// Components
import List from './components/List.jsx';
import Header from './components/Header.jsx';
// App Component
function App() {
const [todos, setTodos] = useState([]); // todos
const [newTodo, setNewTodo] = useState(); // new todos
const loading = useFetch(setTodos, 'http://localhost:4000/initialtodos');
const changeInputData = (e) => { // changeInputData : newTodo에 input에 입력한 내용을 저장하는 함수
setNewTodo(e.target.value);
}
const addTodo = (e) => { // addTodo : 새로운 todo를 배열에 추가하는 함수
e.preventDefault(); // 기본값 form 전송방지
setTodos([...todos, {'title': newTodo, 'todoCode': todos.length, 'contents': '', done: false, edit: false}]);
}
// changeTodoDone
const changeTodoDone = (todoCode) => {
const updateTodos = todos.map(todo => {
if(todo.todoCode === todoCode) {
if(todo.done === true) todo.done = false;
else todo.done = true;
}
return todo;
})
setTodos(updateTodos);
// console.log(updateTodos);
}
useEffect(() => {
console.log("새로운 내용이 추가되었습니다.", todos);
}, [todos]);
return(
<>
<h1>Todo Application</h1>
<Header todos={todos} />
<form action="">
<input type="text" name="" onChange={changeInputData}/>
<button onClick={addTodo}>ADD</button>
</form>
<List todos={todos} loading={loading} changeTodoDone={changeTodoDone} />
</>
);
}
export default App;
List.jsx
// List.jsx
import React from 'react';
import Item from './Item.jsx';
function List({todos, loading, changeTodoDone}) {
let todoList = <div>Loading...</div>;
if(!loading) todoList = todos.map(todo =>
<Item key={todo.todoCode} todo={todo} changeTodoDone={changeTodoDone} />
);
return(
<ul>
{todoList}
</ul>
);
}
export default List;
Item.jsx
Item 컴포넌트에서 Done 상태값이 변경되었다는 것을 시각적으로 보이도록 하자.
// Item.jsx
import React from 'react';
import './Item.css';
function Item({todo, changeTodoDone}) {
// toggleDone : 할 일의 완료/미완료 상태를 표현하는 함수
const toggleDone = (e) => {
changeTodoDone(e.target.dataset.id)
}
// todo의 done 속성값이 true(완료)이면 'done', false(미완료)이면 ''
const ItemClassName = todo.done === true ? 'done' : '';
return(
<li data-id={todo.todoCode} onClick={toggleDone} className={ItemClassName}>{todo.title}</li>
);
}
export default Item;
Item.css
/* Item.css */
.done {
text-decoration: line-through;
font-style: italic;
}
💡 지금까지 각 컴포넌트에 props를 넘기고 넘겨주는 방식으로 todos를 전달해 주었다.
직접 해본 사람은 알겠지만 이 방법은 너무나 번거롭다ㅠ
이 문제를 해결할 수 있는 방법이 Context API와 useContext를 사용하는 것이다.
궁금한 사람은 다음 글로 커몬~!