너의 할 일은。React로 To Do List 만들기

DANO PARK·2022년 5월 2일
10

무작정 따라하기

목록 보기
5/9
post-thumbnail

목표 설정

  • React로 To Do List 만들기
  • input 입력 값 15자로 제한하기
  • To Do List 삭제하기
  • To Do List 10개로 제한하기
  • To Do List LocalStorage에 저장하기

코드 살펴보기

import './App.css';
import { useState, useEffect } from "react";

function App() {
  const [toDo, setToDo] = useState("");
  const [toDos, setToDos] = useState([]);
  const onChange = (event) => setToDo(event.target.value);
  const onSubmit = (event) => {
    event.preventDefault();
    if (toDo === "") {
      return;
    }
    if (toDos.length < 10) {
      setToDos((currentArray) => [toDo, ...currentArray]);
    } else {
      return alert("등록된 리스트가 너무 많습니다.");
    }
    setToDo("");
  };
  const onClick = (idx) => {
    setToDos(toDos.filter((_, toDoIdx) => idx !== toDoIdx));
  }
  useEffect(() => {
    const data = localStorage.getItem('toDoList');
    if (data) {
      setToDos(JSON.parse(data));
    }
  }, []);
  useEffect(() => {
    localStorage.setItem('toDoList', JSON.stringify(toDos));
  }, [toDos]);

  return (
    <div className="box">
      <div className="todo">
        <h1>너의 할 일은。</h1>
        <span className="sub">"아직 한 적 없는 일을, 찾고 있어"</span>
        <form
          className="list" 
          onSubmit={onSubmit}>
          <input 
            onChange={onChange} 
            maxLength={15}
            value={toDo} 
            type="text" 
            placeholder="Write your to do..." 
          />
          <button>
          <span className="material-symbols-outlined">add</span>
          </button>
        </form>
        <ul>
          {toDos.map((item, idx) => (
            <li 
              key={idx}
            >
              {item}
              <button onClick={() => onClick(idx)}>
              <span className="material-symbols-outlined">delete_forever</span>
              </button>
            </li>
          ))}
        </ul>
      </div>
    </div>
  );
}

export default App;

To Do List 만들기

input창에서 onChange를 사용해 입력된 값을 toDosetToDo를 이용해 받는다.

form 태그에 쌓여진 button 태그가 하나일때, button 태그를 활성화한다면 form 태그 전체를 활성화시킬 수 있다. 이것을 이용해 button를 누르면, onSubmit이 실행되도록 하자. onSubmit으로 인해 제출된 toDo는 값이 비었을 경우 아무것도 실행되지 않고, 값이 있을 경우 아래와 같은 코드로 실행된다.

setToDos((currentArray) => [toDo, ...currentArray]);

...은 기존의 배열 값을 의미한다. 아래와 같은 예시를 들어보자

const str1 = [1, 2, 3, 4];
const str2 = [5, str1];
const str3 = [5, ...str1];
  
console.log(str2); // => [5, Array(4)]
console.log(str3); // => [5, 1, 2, 3, 4]

위의 예시대로 ...을 사용하면 기존의 배열에 새로운 값을 더할 수 있다. 즉 기존의 toDo에 새로운 값을 계속 더할 수 있다는 의미다.

toDoonSubmit됐다면, input 창을 비워주기 위해 setToDo("");를 실행해준다. onSubmit으로 등록된 toDo 값은 하단의 ul태그에서 map()을 통해 출력된다.

map() 메서드 알아보기

map()은 배열 내의 모든 요소 각각에 대하여 주어진 함수를 호출한 결과를 모아 새로운 배열을 반환한다. 사용방법은 아래와 같다.

arr.map(callback(currentValue, index, array), thisArg)
  • currentValue : 현재 처리할 요소.
  • index : 처리할 현재 요소의 인덱스.
  • array : map()을 호출한 배열.
  • thisArg : callback을 실행할 때 this로 사용되는 값.

map() 메서드 자세히 알아보기

여기서는 item 값만 줘도 되나, index 값을 따로 주지 않으면 콘솔 창에서 key 값을 줘야한다고 경고 메세지가 뜬다.

여기까지 코드를 작성했으면, 아래와 같이 input 창에 To Do List를 작성하고 To Do List를 ul 태그에 출력할 수 있을 것이다.

input 입력 값 15자로 제한하기

너무 많은 글자를 작성하지 못 하도록 input 태그에 maxLength를 사용하여 아래와 같이 글자 수를 제한할 수 있다.

<input maxLength={15} />

To Do List 삭제하기

To DO List가 추가된 ul 태그의 button 태그에 onClick 기능을 추가해 filter()를 활용한 함수를 실행하게 하자.

filter() 메서드 알아보기

filter()는 배열의 요소를 순차적으로 순회하면서 조건에 일치하는 요소를 모아 새로운 배열을 반환한다. 사용 방법은 아래와 같다.

arr.filter(callback(element, index, array), thisArg)

element : 처리할 현재 요소.
index : 처리할 현재 요소의 인덱스.
array : filter를 호출한 배열.
thisArg : callback을 실행할 때 this로 사용하는 값.

filter()를 테스트를 통과한 요소들로 이루어진 새로운 배열이 반환되며, 어떠한 요소도 통과하지 못하면 빈 배열이 반환된다. 예를들어, 아래와 같은 배열에서 5의 배수인 요소만 추출하고 싶을때 filter() 메서드를 사용하면 된다.

const arr = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const answer = arr.filter(arr => arr > 5)
console.log(answer); // => [6, 7, 8, 9]

onClick(idx)을 통해 버튼을 클릭했을 때 삭제 기능을 넣은 함수를 실행하게 한 뒤 filter() 메서드를 사용해 코드를 아래와 같이 작성해보자. idxtoDos의 배열 번호라고 생각하면 된다.

const onClick = (idx) => {
    setToDos(toDos.filter((_, toDoIdx) => idx !== toDoIdx));
  }

toDos 배열 안에서 filter() 메서드를 사용해서 배열 번호를 toDoidx로 선언해주자. 앞의 element요소는 삭제 기능에 필요없는 부분이므로 언더스코어(_)를 써준다. 작성을 하지않으면 삭제 기능이 이루어지지 않으니 꼭 작성해주자. 그리고 익명함수를 통해 우리가 클릭한 배열 번호(삭제할 To Do)가 현재 toDos가 가지고 있는 배열 번호 중 일치하지 않는 것만 출력해주도록 작성해주면 된다.

이렇게 코드를 작성하면 li에 속한 To Do List가 아래와 같이 삭제된다.

To Do List 10개로 제한하기

위의 To Do List 배열을 더해주는 코드에 if문을 씌워 10개 이하일때 동작하게하고, 10개 초과일시 alert()를 실행해 알림 메세지를 띄워주자.

if (toDos.length < 10) {
      setToDos((currentArray) => [toDo, ...currentArray]);
    } else {
      return alert("등록된 리스트가 너무 많습니다.");
    }

To Do List LocalStorage에 저장하기

To Do List를 LocalStorage에 저장하기 위해서는 useEffect()를 사용해야 한다. useEffect()는 React 컴포넌트가 렌더링될 때마다 특정 작업을 실행할 수 있도록하는 역할을 한다. useEffect()는 컴포넌트가 처음 렌더링될때 한 번 실행되고, 배열로 지정된 useState()의 값이 변경되면 다시 실행된다. 이러한 기능으로 하나의 값이 변동될때마다 전체 컴포넌트를 렌더링하지 않아 부담을 줄일 수 있다. 사용 방법은 아래와 같다.

const [name, setName] = useState();
useEffect(() => {
  console.log("Hello!");  
}, [name]);

첫 번째 렌더링이 될 때 console.log("Hello!")를 한 번, name이 변할 때마다 다시 console.log("Hello!")를 한 번 더 출력하는 코드다. 위의 예시를 이용해 To Do List를 LocalStorage에 저장해보자.

useEffect(() => {
    localStorage.setItem('toDoList', JSON.stringify(toDos));
  }, [toDos]);

위와 같이 'toDoList'라는 이름으로 새로 저장되는 배열 toDos를 LocalStorage에 저장할 수 있다.
이때 LocalStorage는 object를 저장할 수 없기에 JSON.stringify()를 이용해 string으로 바꿔 저장할 수 있다.

useEffect(() => {
    const data = localStorage.getItem('toDoList');
    if (data) {
      setToDos(JSON.parse(data));
    }, []);

저장된 값은 위의 getItem()을 이용해 불러올 수 있는데, 이때 string으로 변환된 값을 JSON.parse()을 이용해 object 값으로 다시 바꿔줘야한다. 또한 LocalStorage가 비어있을 경우 아무 것도 출력되지 않도록 if문을 추가한다.

배포 링크
코드 보기

끝.

profile
단오해서 단호박!

2개의 댓글

comment-user-thumbnail
2022년 5월 5일

그림 배치도 잘하셨네요 👍👍 CSS도 천재되는중

답글 달기
comment-user-thumbnail
2022년 5월 9일

너의 할 일은ㅋㅋㅋㅋㅋㅋㅋㅋ너무 유쾌한 글이라 시리즈 정주행 하고 왔습니다ㅋㅋㅋ

답글 달기