티스토리 뷰
2020/12/08 - [React] - [React] 14. 리덕스로 TodoList구현하기 01
리액트 리덕스를 적용한 투두 리스트 만들기02
지난 시간에 만든 스토어를 적용하여 아래와 같은 투두 리스트를 만들어보겠습니다!
컴포넌트 생성
저는 src/Components 아래에 다음과 같은 컴포넌트들을 생성하여 줄 거예요!
ㅇTodoTemplate : TodoList의 큰 틀을 담당할 컴포넌트
ㅇTodoInput : 새로운 할 일(Todo)을 추가할 수 있는 컴포넌트
ㅇTodoItem : 체크박스, 투두 텍스트, 수정/삭제 버튼을 보여줄 컴포넌트
ㅇTodoList : 할 일들을 모아 리스트로 보여줄 컴포넌트
TodoTemplate
먼저, 투두 리스트의 전체적인 틀을 보여 줄 수 있는 TodoTempate를 아래와 같이 만들어 주었습니다.
// TodoTemplate
import React from "react";
import { Template, Title } from "../Styled/common-styled";
const TodoTemplate = ({ children }) => {
return (
<Template>
<Title> 할 일 </Title>
{children}
</Template>
);
};
export default TodoTemplate;
그리고 아래와 같이 Styled/common-styled.js에 컴포넌트에 지정해줄 스타일을 만들어주었습니다.
// common-style
import styled from "styled-components";
export const Template = styled.div`
margin-top: 5rem;
margin-left: auto;
margin-right: auto;
width: 600px;
background-color: #fff1e6;
padding-top: 2rem;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.15);
`;
export const Title = styled.h1`
text-align : center;
font-size : 3rem;
margin : 0;
`;
그럼 아래와 같이 투두 리스트의 큰 틀을 만들 수 있습니다.
TodoInput
다음은 새로운 투두(Todo)를 추가할 수 있는 TodoInput 컴포넌트를 만들어 보겠습니다.
nextId는 useRef Hooks를 사용해서 구현했습니다.
// TodoInput
import React, { useRef, useState } from "react";
import { AddButton, Input, TodoInputBox } from "../Styled/styled-todoInput";
import { useDispatch } from "react-redux";
import { todoInsert } from "../Reducer/Todo";
const TodoInput = () => {
const [todoInput, setTodoInput] = useState("");
let nextId = useRef(2);
const dispatch = useDispatch();
const onChangeInput = (e) => {
setTodoInput(e.target.value);
};
const onRemove = () => {
setTodoInput("");
};
// Enter키 이벤트
const onKeyPress = (e) => {
if (e.key === "Enter") {
addTodo();
}
};
// Todo 저장
const addTodo = () => {
if (todoInput.length === 0) {
alert("내용을 입력해주세요!");
return;
}
dispatch(todoInsert(nextId.current, todoInput));
nextId.current += 1;
onRemove();
};
return (
<TodoInputBox>
<Input
onChange={onChangeInput}
onKeyPress={onKeyPress}
value={todoInput}
placeholder="할 일을 입력하세요!"
/>
<AddButton onClick={addTodo}>추가</AddButton>
</TodoInputBox>
);
};
export default TodoInput;
그리고 TodoInput에 적용할 스타일을 만들어 줍니다.
// todoInput-styled.js
import styled from "styled-components";
export const TodoInputBox = styled.div`
border-top: 1px solid #eddcd2;
display: flex;
margin: 0 1rem;
padding: 1rem;
`;
export const Input = styled.input`
flex: 1;
outline: none;
border: none;
background: transparent;
`;
export const AddButton = styled.button`
outline: none;
border: none;
border-radius: 20px 20px;
background-color: #ffd5c2;
padding: 1rem 2rem;
color: #e29578;
font-size: 15px;
cursor: pointer;
&:hover {
background-color: #e29578;
color: #ffffff;
}
&:active {
background-color: #e29578;
color: #ffffff;
}
`;
TodoItem
TodoItem 컴포넌트는 TodoList에 하위 컴포넌트로 사용할 예정입니다.
react-icons 라이브러리를 사용하여 컴포넌트를 만들어주었습니다.
// TodoItem
import React from "react";
import {
Button,
CheckBox,
TextBox,
TodoItemBox,
} from "../Styled/todoItem-styled";
import { useDispatch } from "react-redux";
import { todoRemove, todoToggle, todoUpdate } from "../Reducer/Todo";
import { FaRegSquare, FaRegCheckSquare } from "react-icons/fa";
import { TiDeleteOutline } from "react-icons/ti";
import { BiPencil } from "react-icons/bi";
const TodoItem = ({ todo }) => {
const { id, text, isCompleted } = todo;
const dispatch = useDispatch();
return (
<TodoItemBox>
<CheckBox onClick={() => dispatch(todoToggle(id))}>
{isCompleted ? (
<FaRegCheckSquare size="25px" color="#84a98c" />
) : (
<FaRegSquare size="25px" />
)}
</CheckBox>
<TextBox id="text" readOnly={true} value={text} checked={isCompleted} />
<Button>
<BiPencil size="25px" color="#a5a58d" />
</Button>
<Button onClick={() => dispatch(todoRemove(id))}>
<TiDeleteOutline size="30px" color="#e56b6f" />
</Button>
</TodoItemBox>
);
};
export default TodoItem;
styled-components에서도 props를 사용하여 조건을 줄 수 있는데요!
아래 코드에서는 두가지 조건을 추가하여 주었습니다. 첫번째는 체크박스에 props.color가 존재한다면 해당 색상으로! 존재하지 않으면 gray 색상으로 그려줍니다. 두번째는 체크박스에 값이 표시되었다면 해당 텍스트에 취소선 효과를 부여해줍니다.
// TodoItem-styled.js
import styled from "styled-components";
export const TodoItemBox = styled.div`
display: flex;
margin: 0 1rem;
padding: 1rem;
border-bottom: 1px solid #eddcd2;
`;
export const CheckBox = styled.div`
display: inline;
margin: 0 1rem;
cursor: pointer;
color: ${(props) => props.color || "gray"};
`;
export const TextBox = styled.input`
flex: 1;
display: inline;
border: none;
outline: none;
background-color: transparent;
width: 500px;
cursor: default;
text-decoration: ${(props) => (props.checked ? "line-through" : "none")};
color: ${(props) => (props.checked ? "gray" : "black")};
`;
export const Button = styled.div`
display: inline;
width: 30px;
background-color: none;
border: none;
cursor: pointer;
`;
TodoList
위에서 만들어준 TodoItem을 사용하여 리스트를 구성해 줄 거예요!
map 내장 함수를 사용하여 todo를 하나씩 받아와 TodoItem 컴포넌트에 props로 넘겨줍니다.
// TodoList
import React from "react";
import TodoItem from "./TodoItem";
import { useSelector } from "react-redux";
const TodoList = () => {
const todos = useSelector((state) => state.todos);
return (
<div>
{todos.map((todo) => (
<TodoItem key={todo.id} todo={todo} />
))}
</div>
);
};
export default TodoList;
App.js
그리고 마지막으로 src/App.js 에 아래와 같은 구조로 컴포넌트들을 추가하여 줍니다.
// App
import React from "react";
import "./App.css";
import TodoTemplate from "./Components/TodoTemplate";
import TodoInput from "./Components/TodoInput";
import TodoList from "./Components/TodoList";
function App() {
return (
<TodoTemplate>
<TodoInput />
<TodoList />
</TodoTemplate>
);
}
export default App;
아쉬운 점 및 보완할 점!
지금까지 리덕스를 사용한 투두 리스트를 구현해 보았는데요!
조금 아쉬운 점이 있다면 수정 기능을 제대로 구현하지 못한 점입니다. 코드를 좀 더 보완하고 수정 기능도 추가해서 투두 리스트를 제대로 완성해 보아야겠어요! 또한, 스타일을 적용하는 과정에서 아직 부족한 점이 많다는 것을 느꼈어요.! 기능 구현 이외에도 스타일에 관련된 공부를 진행해보아야겠습니다. 감사합니다 :)
'REACT' 카테고리의 다른 글
[React] 17. localStorage와 sessionStorage 사용해보기 (1) | 2020.12.28 |
---|---|
[React] 16. 리덕스로 TodoList구현하기 03 (0) | 2020.12.10 |
[React] 14. 리덕스로 TodoList구현하기 01 (1) | 2020.12.08 |
[React] 13. 리덕스(Redux) 사용해서 카운터 만들기 (0) | 2020.12.04 |
[React] 12. 리덕스(Redux) 개념 정리하기 (0) | 2020.11.30 |
- Total
- Today
- Yesterday