Todo-List 기능 구현)
제목, 내용 입력
완료, 완료취소, 삭제 버튼 구현
1. 리액트 프로젝트 폴더 생성
yarn create react-app todo-list
2. App.jsx에 대략적인 ui 만들기

// App.jsx
import React from "react";
function App() {
return (
<div>
<header>헤더</header>
<main style={{ padding: "20px" }}>
<input setTodos={setTodos} />
</main>
<footer></footer>
</div>
);
}
export default App;
3. Component 분리 및 작성
# yarn에서 uuid 설치
# gitbash에 입력
yarn add uuid
// App.jsx
import React, { useState } from "react";
import "./App.css";
import Header from "./components/Header.jsx";
import Input from "./components/Input";
import { v4 as uuidv4 } from "uuid";
import TodoList from "./components/TodoList";
function App() {
// 리액트에서 데이터를 저장하는 방법 = State
//useState import하기!
//todos : todo라는 객체를 여러개 가지고 있는 배열
const [todos, setTodos] = useState(initialState);
return (
<div>
<Header>Todo List</Header>
{/* 헤더는 하위 컴포넌트, 즉 Header컴포넌트로 들어가서 props에 children으로서 작용함 */}
<main style={{ padding: "20px" }}>
<Input setTodos={setTodos} />
{/* TodoList출력하는 부분 */}
{/* isActive라는 props를 임의로 할당해서 true와 false로 working과 done을 나눔 */}
{/* TodoList.jsx에서 todos를 넘겨줌 */}
<TodoList isActive={true} todos={todos} setTodos={setTodos} />
<TodoList isActive={false} todos={todos} setTodos={setTodos} />
{/* 삭제버튼(Todo.jsx) Component로 setTodos 넘겨주기 */}
{/* Todo의 부모 Component가 TodoList이기 때문에 TodoList에도 넘겨줘야함! */}
</main>
</div>
);
}
export default App;
const initialState = [
{ title: "제목1", contents: "내용1", isDone: false, id: uuidv4() },
{ title: "제목2", contents: "내용2", isDone: false, id: uuidv4() },
{ title: "제목3", contents: "내용3", isDone: false, id: uuidv4() },
]; // id로 순번체크는 하지않음. 대신 uuid를 사용 (install uuid v4 in react 구글링)
// const [todos, setTodos] = useState([]);
// 여기 들어가야 하지만 코드가 길어지면 가독성이 떨어지기 때문에 따로 빼줌
// Header.jsx
import React from "react";
function Header({ children }) {
return <header>{children}</header>;
}
export default Header;
// Input.jsx
import React, { useState } from "react";
import { v4 as uuidv4 } from "uuid";
function Input({ setTodos }) {
const [title, setTitle] = useState("");
const [contents, setContents] = useState("");
const handleSubmitClick = (event) => {
event.preventDefault();
// onSubmit 함수는 한 번 호출되고 나면 페이지를 갱신하기 때문에
// console.log("here!") 코드입력 후 button 클릭 시,
// 콘솔창에 here!문자가 잠깐 나타났다가 사라지는 걸 확인가능
// preventDefault()는 event를 기본적으로 없애주는 함수
// event.preventDefault();를 사용해야 새로고침되지 않고 콘솔창에 here!가 유지된다
const newTodo = {
title: title,
contents: contents,
isDone: false,
id: uuidv4(),
};
// 지금 세팅된 title과 contents를 todos에 넣어주는 작업
setTodos((prev) => {
return [...prev, newTodo];
});
};
const handleTitleChange = (event) => {
setTitle(event.target.value);
};
const handleContentsChange = (event) => {
setContents(event.target.value);
};
return (
<section>
<form onSubmit={handleSubmitClick}>
{/* button이 클릭될 때 onSubmit 함수가 항상 실행되게 */}
제목 <input value={title} onChange={handleTitleChange} />
내용 <input value={contents} onChange={handleContentsChange} />
{/* state는 input과 함께 가야하기 때문에 value={}를 넣어줌 */}
{/* input에 입력할 때마다 State가 갱신되어야 하기 때문에 onChange를 사용 */}
<button>추가</button>
</form>
</section>
);
}
export default Input;
// Todo.jsx
import React from "react";
//삭제버튼!!!!
function Todo({ item, isActive, setTodos }) {
// item, isActive 변수를 props해줘야함
const handleDeleteButton = () => {
setTodos((prev) => prev.filter((t) => t.id !== item.id));
}; //임의의 변수 t의 id와 item의 id가 다르면 갱신이 됨!
//삭제버튼 클릭 시 실행
// setTodos를 쓰면 이전의 값을 가져올 수 있음
// filter로 조건에 맞는 것만 가져오기
const handleSwitchButtonClick = () => {
setTodos((prev) =>
prev.map((t) => {
if (t.id === item.id) {
return { ...t, isDone: !t.isDone };
} else {
return t;
}
})
);
}; // setTodos에서 isDone 값 false와 true를 서로 바꿔줘야함
return (
<div style={{ border: "1px solid black" }} key={item.id}>
<h5>{item.title}</h5>
<p>{item.contents}</p>
<button onClick={handleSwitchButtonClick}>
{isActive ? "완료" : "취소"}
</button>
<button onClick={handleDeleteButton}>삭제</button>
</div>
);
}
export default Todo;
// TodoList.jsx
import React from "react";
import Todo from "./Todo";
function TodoList({ todos, isActive, setTodos }) {
// props로 todos를 받아옴
// map함수를 통해 전체를 출력
return (
<div>
<h4>{isActive === true ? "🔥 Working 🔥" : "✅ Done ✅"}</h4>
{/* isActive===true일때는 working만 나오고 false일때는 done이 나와야 해서,
map을 사용하기 전 filter로 한 번 걸러줌 */}
{/* isDone이 isActive가 아닐 경우에만 출력 */}
{todos
.filter((item) => item.isDone === !isActive)
.map((item) => {
return (
// <div style={{ border: "1px solid black" }}>
// key={item.id}
// <h5>{item.title}</h5>
// <p>{item.contents}</p>
// <button>{isActive ? "완료" : "취소"}</button>
// <button>삭제</button>
// </div> // Todo.jsx로!!
<Todo item={item} isActive={isActive} setTodos={setTodos}></Todo>
// Todo.jsx로 item, isActive, setTodos props 내려주기
);
})}
</div>
);
}
export default TodoList;

'스파르타 개발일지' 카테고리의 다른 글
| 개발일지 20221213 리액트 숙련 강의 2 (0) | 2022.12.13 |
|---|---|
| 개발일지 20221212 리액트 숙련 강의 1 (0) | 2022.12.12 |
| 개발일지 20221208 리액트 입문 3 실습 (0) | 2022.12.08 |
| 개발일지 20221207 리액트 입문 2 (0) | 2022.12.07 |
| 개발일지 20221206 리액트 입문 강의 시작! (0) | 2022.12.06 |