이전 포스팅 [React] todo-list (day13)에 이어
드디어 Todo List를 완성하게 되었다.
첫 리엑트 프로젝트이기 때문에 처음에 많이 헤맸지만 여러 블로그참고 및 React기술매니져님께 질문을 통해 방법을 찾으며 점점 틀을 잡아갈 수 있었다.
위의 사진과 같이 컴포넌트를 배치하였다.
import React from "react";
import "./style.css";
const Todo = ({ todo, remove, onToggle }) => {
const { id, title, body } = todo;
return (
<div className="container">
<div className="todos">
<h3 className="todoTitle">{title}</h3>
<h4 className="todoContents">{body}</h4>
<div className="todoButtons">
{todo.isDone === false ? (
<button className="todoButton" onClick={() => onToggle(id)}>
Nailed it! ✅
</button>
) : (
<button className="todoButton" onClick={() => onToggle(id)}>
Cancel ⛔️
</button>
)}
<button className="todoButton" onClick={() => remove(id)}>
remove ❌
</button>
</div>
</div>
</div>
);
};
export default Todo;
Todo는 isDone의 값이 true일 때와 false일 때로 나누어야 했기 때문에 Working과 Done 두 컴포넌트로 분리를 하였다.
import React from "react";
import Todo from "../todo/Todo";
import "./style.css";
const Working = ({todos, remove, onToggle}) => {
return (
<div className="working">
{todos
.filter((todo) => todo.isDone === false)
.map((todo, idx) => (
<Todo todo={todo} key={idx} remove={remove} onToggle={onToggle}/>
))}
</div>
);
};
export default Working;
import React from "react";
import Todo from "../todo/Todo";
import "./style.css";
const Done = ({todos, remove, onToggle}) => {
return (
<div className="done">
{todos
.filter((todo) => todo.isDone === true)
.map((todo, idx) => (
<Todo todo={todo} key={idx} remove={remove} onToggle={onToggle}/>
))}
</div>
);
};
export default Done;
import React from "react";
import Done from "./Done";
import Working from "./Working";
import "./style.css";
const List = ({todos, remove, onToggle}) => {
//component별로 진행중, 진행완료로 나눈다.
// working -> todo components 호출 (false)
// done -> todo components 호출 (true)
return (
<div className="lists">
<h2 className="status">Work in progress . . 🫡</h2>
<Working todos={todos} remove={remove} onToggle={onToggle}/>
<h2 className="status">Done ! 😎</h2>
<Done todos={todos} remove={remove} onToggle={onToggle}/>
</div>
);
};
export default List;
import React from 'react';
import './style.css';
import icon from './logo192.png';
const Header = () => {
return (
<div className='header'>
<a href='/'>My Todo List</a>
<p>React <img style={{height:'25px', transform:'translateY(2px)'}} src={icon} alt="Icon"/></p>
</div>
);
};
export default Header;
import React from 'react';
import './style.css';
const Form = ({title, body, onChangeHandler, onSubmitHandler}) => {
return (
<div className='formDiv'>
<form className='todoInput'>
<label>Title :</label>
<input name='title' type='text' value={title} onChange={onChangeHandler}/>
<label>Contents :</label>
<input name='body' type='text' value={body} onChange={onChangeHandler}/>
<button id="submit" type='submit' onClick={onSubmitHandler}>Submit</button>
</form>
</div>
);
};
export default Form;
import React, { useState } from "react";
import Form from "../form/Form";
import List from "../list/List";
import "./style.css";
const Layout = () => {
const [input, setInput] = useState({
title: "",
body: "",
});
const { title, body } = input;
const onChangeHandler = (e) => {
const { value, name } = e.target;
setInput({
...input,
[name]: value,
});
};
const onSubmitHandler = (e) => {
e.preventDefault();
if(!input.title||!input.body) return;
const num = todos.length;
const todo = {
id: num + 1,
title,
body,
isDone: false,
};
//배열 항목 추가하기
setTodos([...todos, todo]);
// setTodos(todos.concat(todo)) concat() 메서드는 인자로 주어진 배열이나 값들을 기존 배열에 합쳐서 새 배열을 반환합니다.
setInput({
title: "",
body: "",
});
};
const [todos, setTodos] = useState([
{
id: 1,
title: "study React",
body: "Finish todo list",
isDone: false,
},
{
id: 2,
title: "wake up Early",
body: "to study",
isDone: true,
},
]);
const remove = (id) => {
setTodos(todos.filter((todo) => todo.id !== id));
};
const onToggle = (id) => {
//todo.id가 파라미터로 일치하지 않는 원소만 추출해서 새로운 배열을 만듬
// = todo.id가 id인 것을 제거함
setTodos(todos.map(
todo => todo.id === id
? {...todo, isDone: !todo.isDone} : todo
));
};
return (
<div className="layOut">
<Form
title={title}
body={body}
onChangeHandler={onChangeHandler}
onSubmitHandler={onSubmitHandler}
/>
<List todos={todos} remove={remove} onToggle={onToggle} />
</div>
);
};
export default Layout;
import React from 'react';
import Layout from '../components/layout/Layout';
import Header from '../components/header/Header';
const TodoList = () => {
return (
<div>
<Header/>
<Layout/>
</div>
);
};
export default TodoList;
처음에 Form에서 입력을 받아 부모 component인 Layout으로 Data를 전달하고 자녀 컴포넌트인 List로 뿌려주기 위해 노력하였으나 jsx 문법이 익숙지 않아 헤매던 중 가장 상위 component에서 모든 함수를 작성하는 방법이 더 편할 것 같다는 생각을 하게 되었고 그 이후로는 순조롭게 진행이 된 것 같다.
또 한 가지 쉽지 않았던 부분은 Input이 두 개라는 점이었다.
하지만 useState({title:'', body:''})를 통해 동시에 값을 전달받을 수 있는 방법을 터득하고 나니 크게 어렵지 않았던 것 같다.