React-TodoList

January·2022년 8월 1일
0

Frontend

목록 보기
16/31

할일 정리

  1. Todo Item (Item, Remove)
  2. Todo List
  3. Todo Add

List 표시

TodoList 에서는 데이터를 토대로 TodoItem 을 map 을 활용해서 보여준다. 각각의 할 일 데이터는 아래처럼 todoData 라는 이름의 배열에 저장되도록 작성한다. 후에는 키 값을 초기화값으로 수정해줘야한다.

// todoData
const [todoData, setTodoData] = useState([할일])

할일 Id값을 받아서 완료 여부를 setTodoData로 실행한다.

<div>
  {todoData.map((itemData) => {
     return(
       <TodoItem key={itemData.id} itemData={itemData}/>
     )
  })}
</div>

Item 표시

props로 받은 데이터를 표시되도록 작성해준다.

function TodoItem({itemData}) {
  const {id, date, content, checked} = itemData

  return (
    <div>
        <p>{date}</p>
        <p>{content}</p>
    </div>
  )
}

Todo Add

할일을 추가하는 것은 Input Value를 onChange 기반으로 userInput에 받을 수 있도록 작성한다.

function TodoAdd() {
  const [userInput, setUserInput] = useState({date: '', content: ''})

  const userInputHandler = (e) => {
    const {name, value} = e.target
    setUserInput({...userInput, [name]:value})
  }

  return (
    <div>
        <input type='date' name='date' onChange={userInputHandler}/>
        <input name='content' onChange={userInputHandler}/>
        <button>할일 추가</button>
    </div>
  )
}

Todo Id로 할일에 추가 순서가 될 수 있도록 추가될때마다 Id값에 +1이 된다. Id값은 표시되지 않고 데이터 추가와 제거만 되는 값이기 때문에 useRef로 만들어준다.

function TodoList() {
  const todoId = useRef(1);
  const [todoData, setTodoData] = useState([{id: 1, date:'2022-07-28', content:'강의하기', checked:true}])

  return (
    <div>
        <TodoAdd todoId={todoId} todoData={todoData} setTodoData={setTodoData}/>
        {todoData.map((itemData) => {
            return(
                <TodoItem key={itemData.id} itemData={itemData} />
            )
        })}
    </div>
  )
}

props로 todoAdd에 내려보낸 Id값을 todoData에 추가해준다. 기존 있던 todo는 전개연산자로 새로운 배열에 들어가고 추가된 todo는 뒤에 추가된다.

// todoAdd
const todoAddHandler = (userInput) => {
    setTodoData([...todoData, {id:todoId.current, date:userInput.date, content: userInput.content, checked:false}])
    todoId.current += 1
  }
  
<button onClick={() => todoAddHandler(userInput)}>추가하기</button>

Todo Remove

Todo Id값을 받아서 삭제하는 todo를 필터링한다.

// todoList
const todoRemoveHandler = (id) => {
    setTodoData(todoData.filter(itemData => itemData.id !== id))
  }

함수 상위 컴포넌트에서 만들고 props로 내려주는 이유는 todoItem이 여러개 렌더링되면서 제거함수도 여러개 생성되기 때문에 이런것을 방지해주기 위해서이다..

// todoList
return (
    <div>
        <TodoAdd todoId={todoId} todoData={todoData} setTodoData={setTodoData}/>
        {todoData.map((itemData) => {
            return(
                <TodoItem key={itemData.id} itemData={itemData} todoRemoveHandler={todoRemoveHandler}/>
            )
        })}
    </div>
  )

Id값을 인자로 넣어줘서 해당 아이디를 가진 아이템을 삭제해주도록 한다.

// todoItem
return (
    <div>
        <p>{date}</p>
        <p>{content}</p>
        <button onClick={() => todoRemoveHandler(id)}>제거하기</button>
    </div>
  )

todo Check

특정 할일을 완료하는 기능이다. map 함수와 조건문을 활용해서 인자로 들어온 아이디와 일치하는 item의 checked 값을 느낌표 연산자로 변경해준다.

  const todoCheckHandler = (id) => {
    setTodoData(todoData.map(itemData => itemData.id === id ? {...itemData, checked: !itemData.checked} : itemData))  
  }

todoItem에 완료 버튼을 만들어준다.

return (
    <div>
        <p>{date}</p>
        <p>{content}</p>
        <button onClick={() => todoCheckHandler(id)}>{checked ? <>완료</> : <>미완료</>}</button>
        <button onClick={() => todoRemoveHandler(id)}>제거하기</button>
    </div>
  )

todoList 완성

import {useState, useRef} from 'react'
import TodoAdd from "./TodoAdd"
import TodoItem from "./TodoItem"

function TodoList() {
  const todoId = useRef(2);
  const [todoData, setTodoData] = useState([{id: 1, date:'2022-07-28', content:'강의하기', checked:true}])

  const todoRemoveHandler = (id) => {
    setTodoData(todoData.filter(itemData => itemData.id !== id))
  }

  const todoCheckHandler = (id) => {
    setTodoData(todoData.map(itemData => itemData.id === id ? {...itemData, checked: !itemData.checked} : itemData))  
  }

  return (
    <div>
        <TodoAdd todoId={todoId} todoData={todoData} setTodoData={setTodoData}/>
        {todoData.map((itemData) => {
            return(
                <TodoItem key={itemData.id} itemData={itemData} todoCheckHandler={todoCheckHandler} todoRemoveHandler={todoRemoveHandler}/>
            )
        })}
    </div>
  )
}

export default TodoList

styled-components

todoList

스타일

import styled from 'styled-components'

export const TodoContainer = styled.div`
  ${({ theme }) => theme.common.flexColumnStart};

  background-color: ${({ theme }) => theme.palette.red};
  border-radius: 10px;
  color: white;
  width: 50rem;
  height: 33rem;
  margin: 3rem auto;

  font-family: 'NotoSansBold';
`

export const TodoTitle = styled.p`
  font-size: ${({ theme }) => theme.fontSizes.subtitle};
`

스타일 적용
<S.TodoContainer>, <S.TodoTitle>로 작성해서 특정 요소에 스타일을 입혀준다.

import * as S from './style'

return (
    <S.TodoContainer>
      <S.TodoTitle>나만의 Todo List</S.TodoTitle>
      <TodoAdd todoId={todoId} todoData={todoData} setTodoData={setTodoData} />
      {todoData.map((itemData) => {
        return (
          <TodoItem
            key={itemData.id}
            itemData={itemData}
            todoCheckHandler={todoCheckHandler}
            todoRemoveHandler={todoRemoveHandler}
          />
        )
      })}
    </S.TodoContainer>
  )

react-icons

react-icons 여기서 필요한 아이콘이 있는지 찾아본 후에 있다면 라이브러리 설치를 해준다. yarn add react-icons 사용할 아이콘을 import해주고 html 요소로 표시해준다.

// todoItem
import { GrCheckbox, GrCheckboxSelected } from 'react-icons/gr'
import { AiOutlineCloseCircle } from 'react-icons/ai'

return (
    <S.ItemContainer>
      <S.ItemButton onClick={() => todoCheckHandler(id)}>
        {checked ? <GrCheckboxSelected /> : <GrCheckbox />}
      </S.ItemButton>
      <S.ItemText>{date}</S.ItemText>
      <S.ItemText>{content}</S.ItemText>
      <S.ItemButton onClick={() => todoRemoveHandler(id)}>
        <AiOutlineCloseCircle />
      </S.ItemButton>
    </S.ItemContainer>
  )

완료된 할일 소팅
완료하면 목록 하단으로 배치가된다.

const [sortedData, setSortedData] = useState([])

useEffect(() => {
    setSortedData(todoData.sort((a, b) => a.checked - b.checked))
  }, [todoData])

0개의 댓글