티스토리 뷰

728x90

 

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;

 

아쉬운 점 및 보완할 점!

지금까지 리덕스를 사용한 투두 리스트를 구현해 보았는데요! 

조금 아쉬운 점이 있다면 수정 기능을 제대로 구현하지 못한 점입니다. 코드를 좀 더 보완하고 수정 기능도 추가해서 투두 리스트를 제대로 완성해 보아야겠어요! 또한, 스타일을 적용하는 과정에서 아직 부족한 점이 많다는 것을 느꼈어요.! 기능 구현 이외에도 스타일에 관련된 공부를 진행해보아야겠습니다. 감사합니다 :)

728x90
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크