React: To Do List 만들기 연습

summereuna🐥·2022년 2월 24일
0

React JS

목록 보기
15/69

useState, useEffect, prop을 사용하여 To Do List를 만들어 보자.

part 1

input을 만들고 input의 value 값이 변하는 것에 따라 state가 변하도록 작성

import { useState } from "react";

function App() {
  const [toDo, setToDo] = useState("");
  const onChange = (event) => setToDo(event.target.value);
  //console.log(toDo);
  return (
    <div>
      <input
        onChange={onChange}
        value={toDo}
        type="text"
        placeholder="Write your to do..."
      ></input>
    </div>
  );
}

export default App;

form 안에 input을 넣고 button 추가

  • form에 onSubmit 이벤트 리스너 추가
  • form의 button 클릭시 submit 되는데 그 때 자동 새고 되는 거 막기 위해 아래 코드 작성
    event.preventDefault();
import { useState } from "react";

function App() {
  const [toDo, setToDo] = useState("");
  const onChange = (event) => setToDo(event.target.value);
  //form의 button 클릭시 submit 되는데 그 때 자동 새고 되는 거 막기 위해 아래 코드 작성
  const onSubmit = (event) => {
    event.preventDefault();
    //console.log(toDo);
  };
  return (
    <div>
      <form onSubmit={onSubmit}>
        <input
          onChange={onChange}
          value={toDo}
          type="text"
          placeholder="Write your to do..."
        ></input>
        <button>Add To Do</button>
      </form>
    </div>
  );
}

export default App;

toDo 비어 있으면 submit 되지 않도록 return 시키고, submit되고 나서는 input 값 비워 주자.

  • toTo 비어 있으면 submit 되지 않도록 return 시키기 위해 if 문 사용하면 된다.
if (toDo === "") {
  return;
}
  • submit되고 나서는 input 값 비워주기 위해서는 간단하게 모디파이어에 빈 값 주면 된다.
    setToDo("");
    와... input.value 뭐 이렇게 끌어와서 안써도 state 바뀌니 너무 좋네..리액트 짱이네..ㅠㅡㅠ
import { useState } from "react";

function App() {
  const [toDo, setToDo] = useState("");
  const onChange = (event) => setToDo(event.target.value);
  //console.log(toDo);
  //form의 button 클릭시 submit 되는데 그 때 자동 새고 되는 거 막기 위해 아래 코드 작성
  const onSubmit = (event) => {
    event.preventDefault();
    //console.log(toDo);
    //toTo 비어 있으면 submit 되지 않도록 return 시키자.
    if (toDo === "") {
      return;
    }
    //그리고 submit되고 나서는 input 값 비워주자. 그러려면 모디파이어에 빈 값 주면 된다.
    setToDo("");
  };
  return (
    <div>
      <form onSubmit={onSubmit}>
        <input
          onChange={onChange}
          value={toDo}
          type="text"
          placeholder="Write your to do..."
        ></input>
        <button>Add To Do</button>
      </form>
    </div>
  );
}

export default App;

여러개의 toDo 받을 수 있는 array 만들기

import { useState } from "react";

function App() {
  //1. input value 값으로 toDo 받아오기
  const [toDo, setToDo] = useState("");
  //2. 여러개의 toDo 담는 array, 디폴트 값은 비어 있는 array로 작성
  const [toDos, setToDos] = useState([]);
  //toDo를 추가할 때 이 array에 추가해 주기
  const onChange = (event) => setToDo(event.target.value);
  //form의 button 클릭시 submit 되는데 그 때 자동 새고 되는 거 막기 위해 아래 코드 작성
  const onSubmit = (event) => {
    event.preventDefault();
    //toTo 비어 있으면 submit 되지 않도록 return 시키자.
    if (toDo === "") {
      return;
    }
    //그리고 submit되고 나서는 input 값 비워주자. 그러려면 모디파이어에 빈 값 주면 된다.
    setToDo("");
  };
  return (
    <div>
      <form onSubmit={onSubmit}>
        <input
          onChange={onChange}
          value={toDo}
          type="text"
          placeholder="Write your to do..."
        ></input>
        <button>Add To Do</button>
      </form>
    </div>
  );
}

export default App;

📝 state를 수정하는 방법

  • 바닐라 자바스크립트에서는 toDos가 array 이기 때문에 toDos.push()를 사용하면 된다.
  • ❗️ 하지만 리액트에서는 state를 직접 수정하지 않는다는 것을 기억하자!
  • toDo ="" 라고 작성하지 않고, 함수를 사용하여 state를 수정한다.
  • 따라서 toDo를 수정하든, toDos를 수정하든, state를 수정하고 싶다면 수정하는 함수, 즉 모디파이어를 사용해야 한다.

array를 직접 수정하지 않고 setToDos()로 array에 element 추가하는 방법

const food = [1,2,3,4];
//어떻게 새로운 어레이를 만들 수 있을까?
[5, food];
//라고 작성할 경우 [6, Array(4)]라고 뜬다.

//5에 food 어레이의 elements를 더해 새로운 어레이를 만들어야 한다.
//그러기 위해서는 아래와 같이 적으면 된다.
[5, ...food]

import { useState } from "react";

function App() {
  //1. input value 값으로 toDo 받아오기
  const [toDo, setToDo] = useState("");
  //2. 여러개의 toDo 담는 array, 디폴트 값은 비어 있는 array로 작성
  const [toDos, setToDos] = useState([]);
  const onChange = (event) => setToDo(event.target.value);
  //form의 button 클릭시 submit 되는데 그 때 자동 새고 되는 거 막기 위해 아래 코드 작성
  const onSubmit = (event) => {
    event.preventDefault();
    //toTo 비어 있으면 submit 되지 않도록 return 시키자.
    if (toDo === "") {
      return;
    }
    //이전값 받아오기
    // 첫 번째 인자로 현재 state 받아오는 함수 적어주자.
    //그리고 새로운 array 받아와서 return해주자. 이 부분이 상당히 중요하다. state는 항상 새로운 거여야 한다.
    //그리고 그 새로운 []에는 방금 적은 toDo와, 현재 toDos의 어레이의 엘리먼트를 넣어주면 된다. 이렇게 toDos가 방금 적은 toDo와 기존에 입력된 toDos의 엘리먼트가 합쳐진 새로운 어레이로 업뎃되게 해주자.
    setToDos((currentArray) => [toDo, ...currentArray]);
    //그리고 submit되고 나서는 input 값 비워주자. 그러려면 모디파이어에 빈 값 주면 된다.
    setToDo("");
  };
  //적었던 값이 어레이에 잘 들어가고 있는지 확인해 보자.
  console.log(toDos);
  return (
    <div>
      <form onSubmit={onSubmit}>
        <input
          onChange={onChange}
          value={toDo}
          type="text"
          placeholder="Write your to do..."
        ></input>
        <button>Add To Do</button>
      </form>
    </div>
  );
}

export default App;

toDos가 Array이기 때문에 어레이 안에 몇개 들었는지 가져와서 볼 수 있다.

  1. h1 태그로 제목을 적어주자.
    <h1>My To Do List ({toDos.length})</h1>

jsx에 자바스크립트 넣고 싶으면 {} 중괄호 안에 넣으면 된다.

요약

//모디파이어 setToDo로 비어 있는 String 값을 보내면, toDo는 빈 String 값으로 업데이트 된다.
setToDo("");

//🔥모디파이어로 단순히 값만 보내는 것이 아닌 함수를 보낼 수도 있다.
//함수를 보낼 때 react.js는 🔥함수의 첫 번째 argument로 현재 state를 보낸다.
//이는 현재 state를 계산하거나 새로운 state를 만드는데 사용할 수 있다.
setToDos((currentArray) => [toDo, ...currentArray]);
//즉 첫 번째 인자로 보낸 currentArray의 값은 === toDos 어레이인 것 ㅇㅇ!
//따라서 toDo와 toDos어레이 안의 element를 새로운 toDos 어레이로 return한다.(업데이트 한다.)

part 2.


array로 부터 동일한 component에 있는 많은 것들을 render하기


toDos Array 안에 있는 각각의 element를 component로 만들어 보자.

  1. form 태그 밑에 <hr /> (horizontal rule) 작성하고 그 밑에 ul 태그를 작성한다.

  2. ul 태그 안에 자바스크립트 사용할 수 있도록 {} 사용해 toDos 배열 가져오자.

//생략
  return (
    <div>
      <h1>My To Do List ({toDos.length})</h1>
      <form onSubmit={onSubmit}>
        <input
          onChange={onChange}
          value={toDo}
          type="text"
          placeholder="Write your to do..."
        ></input>
        <button>Add To Do</button>
      </form>
      <hr />
        <ul>
          {toDos}
        </ul>
    </div>
  );
}

export default App;
  1. map()활용해 toDos 가져오기

자바스크립트 함수인 map() 사용하기

["item1", "item2", "item3"].map(배열의 모든 item에 대해 실행되는 함수)

  • array.map(fn)은 array에 있는 item을 내가 원하는 것으로 바꿔주는 역할을 한다.
  • 배열의 모든 item에 대해 실행되는 함수에서, 무엇을 return 하든 그 return한 값이 새로운 array에 들어간다.
  • 따라서 array의 item이 3개라면, 그 함수가 3번 실행된다.
  • 결국 그 함수로부터 내가 return한 값을 새로운 array에 넣어준다.
  • 예시

그런데 이렇게 굳이 쓸게 있을까?
보다시피 기존의 ite으로 접근할 수가 없게되었넹..^^..

  • 다행히 map은 함수의 첫 번째 인자현재의 item을 가져올 수 있다.
    즉 map의 함수의 첫번째 인자는 진행되고 있는 순서에 맞는 item이다. 그래서 원래의 item 자체를 return 할 수도 있다.
  • 이렇게 하면 각각의 아이템이 대문자인 새로운 array가 return된다.
    ["rm", "jin", "suga"].map((item) => item.toUpperCase())

map()을 활용하여 어레이 안의 각각의 아이템을 컴포넌트로 만들어 보자.

  • toDos 어레이 안의 각각의 아이템인 toDo를 함수의 첫번째 인자로 보내고 각 아이템인 toDo를 리스트로 return하면 된다.
    {toDos.map((toDo) => <li>{toDo}</li>)}
import { useState } 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;
    }
    setToDos((currentArray) => [toDo, ...currentArray]);
    setToDo("");
  };
  console.log(toDos);
  return (
    <div>
      <h1>My To Do List ({toDos.length})</h1>
      <form onSubmit={onSubmit}>
        <input
          onChange={onChange}
          value={toDo}
          type="text"
          placeholder="Write your to do..."
        ></input>
        <button>Add To Do</button>
      </form>
      <hr />
        <ul>
          {toDos.map((toDo) => <li>{toDo}</li>)}
        </ul>
    </div>
  );
}

export default App;

오케이! 이렇게 되면 [] 안에 각각의 아이템이 리스트 형태로 들어가 진 모양인거다.

<ul>
  <li>{item}</li>
  <li>{item}</li>
  <li>{item}</li>
</ul>

뭐 이런 모양새라고 생각하면 되겠다.

잘되긴 하는데 콘솔에 경고가 뜬다.

  • 경고: 같은 컴포넌트의 리스트를 render할 때는 key라는 prop을 넣어주라고 한다.
    이는 기본적으로 리액트가 list에 있는 모든 item들을 인식하기 때문이다.

  • 해결: li에 key를 prop으로 넣어주면 된다.
    map()에서 함수의 인자 부분을 살펴보면 key 값으로 쓸만한 게 보인다.

{toDos.map((toDo, index) => (
          <li key={index}>{toDo}</li>
  ))}

두 번째 argument로 index를 보내서 key값으로 사용하면 unique한 키값을 얻을 수 있다.

요약


array를 가져와서 그 array의 item을 변경해서 li되게 하기.

이야... 데이터는 바꿔주면되고 ui는 자동으로 바뀐다....^~^ 자바스크립트에서 넘어오니 이렇게 멋진 세상이...!

extra (+)

to do list 순서대로 나오게 하기

[toDo, ...currentArray]라고 적은 순서 바꿔서 [...currentArray, toDo]라고 적으면 to do input에 적은 순서대로 나온다. ^^! 이렇게 간단한데서 차이가 나는구나...!

to do list 삭제 기능

1. 첫 번째 방법


현재 로컬스토리지를 활용해 저장하는 것은 아니기 때문에 간단하게 하기 위해 부모 요소를 찾아서 없애주면 된다.

import { useState } from "react";

function App() {
  //1. input value 값으로 toDo 받아오기
  const [toDo, setToDo] = useState("");
  //2. 여러개의 toDo 담는 array, 디폴트 값은 비어 있는 array로 작성
  const [toDos, setToDos] = useState([]);
  const onChange = (event) => setToDo(event.target.value);
  //form의 button 클릭시 submit 되는데 그 때 자동 새고 되는 거 막기 위해 아래 코드 작성
  const onSubmit = (event) => {
    event.preventDefault();
    //toTo 비어 있으면 submit 되지 않도록 return 시키자.
    if (toDo === "") {
      return;
    }
    //setToDos에 기존에 가지고 있던 currentArray의 element들과 toDo 넣어 return하기
    setToDos((currentArray) => [...currentArray, toDo]);
    //그리고 submit되고 나서는 input 값 비워주자. 모디파이어에 빈 값 주면된다.
    setToDo("");
  };
  //투두리스트 삭제하기
  const deleteToDo = (event) => {
    //console.log(event.target.parentElement);
    const li = event.target.parentElement;
    li.remove();
  };
  return (
    <div>
      <h1>My To Do List ({toDos.length})</h1>
      <form onSubmit={onSubmit}>
        <input
          onChange={onChange}
          value={toDo}
          type="text"
          placeholder="Write your to do..."
        ></input>
        <button>Add To Do</button>
      </form>
      <hr />
      <ul>
        {toDos.map((toDo, index) => (
          <li key={index}>
            {toDo}
            <button onClick={deleteToDo}></button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default App;

2. 두 번째 방법

단순히 부모 요소를 삭제하는 것이 아닌 배열 안에 있는 index와 삭제할 index(버튼의 li)를 찾아서 삭제할 경우에는 filter함수를 사용하면 된다.

filter() 메서드는 주어진 함수의 테스트를 통과하는 모든 요소를 모아 새로운 배열로 반환한다.

  • filter() 예시
const words = ['spray', 'limit', 'elite', 'exuberant', 'destruction', 'present'];
const result = words.filter(word => word.length > 6);
console.log(result);
// expected output: Array ["exuberant", "destruction", "present"]
  1. <button onClick={() => deleteToDo(index)}>❌</button>
    ❌ 버튼을 누르면 deleteToDo()함수로 index를 보낸다.

  2. deleteToDo()함수에 index값을 인자로 받아 온다.

const deleteToDo = (index) => {
    setToDos(toDos.filter((toDo, toDoIndex) => index !== toDoIndex));
  };
  • setToDos() 모디파이어를 활용하여 toDos 배열에 필터링을 돌려 값을 반환받아 삭제된 것 같은 연출을 해주면 된다.
    즉, 클릭한 ❌ 버튼이 들어있는 엘리먼트의 index 값을 필터링해서 배열에서 없애고 반환하면 된다.
  • toDos.filter((toDo, toDoIndex) => index !== toDoIndex)
    toDos에서 toDo와 toDoIndex를 찾아 온 후,
  • 클릭한 ❌ 버튼이 들어있는 엘리먼트의 index값과
    toDos 배열에 있는 element의 index 값인 toDoIndex을 비교하여,
  • !==
    index 값이 다른 것만 모아서 반환한다.
    즉, index 값이 같은 건 반환하지 않기 때문에 클릭한 ❌ 버튼이 들어있는 엘리먼트는 최종적으로 toDos 어레이 안에서 없어진 채로 업데이트 된다.

이렇게 하면 복잡하지만 index를 활용해 볼 수 있다는 점..^ㅇ^!

  • 그리고 또 한가지!
    <button onClick={() => deleteToDo(index)}>❌</button>
    () => deleteToDo(index) 이렇게 쓰는 이유는 "바로 실행"되지 않고 클릭을 기다리는 함수로 쓰기 위함이다. 왠지는 아직 잘 모르겠다.🥺🥲
import { useState } from "react";

function App() {
  //1. input value 값으로 toDo 받아오기
  const [toDo, setToDo] = useState("");
  //2. 여러개의 toDo 담는 array, 디폴트 값은 비어 있는 array로 작성
  const [toDos, setToDos] = useState([]);
  const onChange = (event) => setToDo(event.target.value);
  //form의 button 클릭시 submit 되는데 그 때 자동 새고 되는 거 막기 위해 아래 코드 작성
  const onSubmit = (event) => {
    event.preventDefault();
    //toTo 비어 있으면 submit 되지 않도록 return 시키자.
    if (toDo === "") {
      return;
    }
    //setToDos에 기존에 가지고 있던 currentArray의 element들과 toDo 넣어 return하기
    setToDos((currentArray) => [...currentArray, toDo]);
    //그리고 submit되고 나서는 input 값 비워주자. 모디파이어에 빈 값 주면된다.
    setToDo("");
  };
  //투두리스트 삭제하기
  const deleteToDo = (index) => {
    setToDos(toDos.filter((toDo, toDoIndex) => index !== toDoIndex));
  };
  return (
    <div>
      <h1>My To Do List ({toDos.length})</h1>
      <form onSubmit={onSubmit}>
        <input
          onChange={onChange}
          value={toDo}
          type="text"
          placeholder="Write your to do..."
        ></input>
        <button>Add To Do</button>
      </form>
      <hr />
      <ul>
        {toDos.map((toDo, index) => (
          <li key={index}>
            {toDo}
            <button onClick={() => deleteToDo(index)}></button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default App;

https://ko.reactjs.org/docs/lists-and-keys.html
리액트- 리스트와 키 관련 공식문서

profile
Always have hope🍀 & constant passion🔥

0개의 댓글