React 기초 [10] : To-do-list

yoneeki·2023년 10월 1일

ReactBeginnerMovies

목록 보기
10/14

자바스크립트의 배열과 스프레드 연산자

  • 스프레드 연산자를 통해 배열을 복사하거나 조작할 때, 기존 배열은 변경되지 않으며 새로운 배열이 생성됩니다. 이를 통해 데이터 불변성을 유지하고 예기치 않은 부작용을 방지하는 데 도움이 됩니다.

배열의 생성과 복사

const originalArray = [1, 2, 3];
const copiedArray = [...originalArray];
  • 스프레드 연산자를 사용하여 originalArray의 모든 요소를 copiedArray에 복사합니다. 이제 copiedArray는 originalArray와 동일한 요소를 가지고 있지만 서로 다른 배열입니다.

배열 연결

const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
const combinedArray = [...array1, ...array2];
  • 스프레드 연산자를 사용하여 두 개의 배열을 연결하여 combinedArray에 저장합니다.

요소 추가

const originalArray = [1, 2, 3];
const newArray = [...originalArray, 4];
  • 스프레드 연산자를 사용하여 새 요소(여기서는 4)를 기존 배열에 추가한 후, 새로운 배열 newArray를 생성합니다.

배열의 일부 추출

const originalArray = [1, 2, 3, 4, 5];
const slicedArray = [...originalArray.slice(0, 3)];
  • 스프레드 연산자를 사용하여 배열의 일부를 추출하고 복사합니다. 위 예제에서는 인덱스 0부터 2까지의 요소를 추출하여 slicedArray에 저장합니다.

배열 요소 변경

const originalArray = [1, 2, 3];
const modifiedArray = originalArray.map(item => item * 2);
  • map 함수를 사용하여 originalArray의 모든 요소를 2배로 곱한 새로운 배열 modifiedArray를 생성합니다.

자바스크립트의 map 함수

  • JavaScript의 map() 함수는 배열을 순회하면서 각 요소에 대해 지정된 콜백 함수를 호출하고, 콜백 함수의 반환 값으로 이루어진 새로운 배열을 생성합니다. map() 함수는 배열을 변환하거나 새로운 배열을 생성할 때 주로 사용됩니다.
  • map() 함수는 원래 배열을 변경하지 않고 새로운 배열을 생성하기 때문에 데이터 불변성을 유지하면서 배열을 변환할 수 있으며, 함수형 프로그래밍 패턴과 잘 어울립니다. 이것은 React에서 상태나 props를 다룰 때 유용하게 활용됩니다.
const newArray = originalArray.map(callback(currentValue, index, array) {
  // 반환할 값 계산
  return /* 계산한 값 */;
});
  • originalArray: 순회할 배열입니다.
  • callback: 각 요소에 대해 호출될 함수로, 다음 세 가지 인자를 받습니다.
    1. currentValue: 현재 순회 중인 요소의 값.
    2. index: 현재 순회 중인 요소의 인덱스.
    3. array (선택사항): map() 메서드를 호출한 배열.
  • map() 함수는 순회하며 각 요소에 대해 callback 함수를 호출하고, callback 함수가 반환하는 값을 새로운 배열에 저장합니다. 그리고 최종적으로 새로운 배열을 반환합니다.
const numbers = [1, 2, 3, 4, 5];

const squaredNumbers = numbers.map((number) => {
  return number * number;
});

console.log(squaredNumbers); // [1, 4, 9, 16, 25]
  • 위 예제에서 map() 함수는 numbers 배열의 각 숫자를 제곱하여 squaredNumbers 배열을 생성합니다.
const numbers = [1, 2, 3, 4, 5];

const squaredNumbers = numbers.map((idx) => {
  return idx * idx;
});

console.log(squaredNumbers); // [1, 4, 9, 16, 25]

  • number가 아니라 idx라고 코드를 작성해도 결과는 동일하다. item이라는 argument명도 자주 사용된다.
  • useState의 두 번째 argument인 set 함수에서 state 변경에 대한 데이터를 조작할 때, current라 적든, prev라 적든, banana라 적든 아무 상관 없이 기능이 수행되는 것처럼 말이다.

To-do-list (1)



  • form은 그 자체로 submit 이벤트를 갖고 있기 때문에, form 내부에 있는 버튼을 누르기만 해도 컴포넌트를 리프레시될 것이다.
  • 그리고 나는 그러한 기능을 막고 싶다.


  • 그래서 나는 event.preventDefault() 라는 함수를 이용하였다.

    event.preventDefault()는 웹 브라우저의 기본 동작을 중단시키는 메서드입니다. 이 메서드를 호출하면 이벤트의 기본 동작이 발생하지 않고, 대신에 개발자가 원하는 동작을 수행할 수 있습니다. 일반적으로 이 메서드는 다음과 같은 상황에서 사용됩니다:

    • 폼 제출 이벤트에서: 웹 폼을 제출할 때, 브라우저는 페이지를 새로고침하거나 다른 페이지로 이동하려고 시도합니다. 이를 방지하기 위해 event.preventDefault()를 사용하여 제출 동작을 중단하고, 폼 데이터를 수집하거나 AJAX 요청을 보낼 수 있습니다.
    • 앵커(링크) 클릭 이벤트에서: 일반적으로 앵커(링크)를 클릭하면 브라우저는 해당 링크의 URL로 이동하려고 합니다. 그러나 event.preventDefault()를 사용하면 페이지 이동을 막고, 클릭 이벤트에 사용자 지정 로직을 추가할 수 있습니다.
    • 드래그 앤 드롭 이벤트에서: 파일을 웹 페이지로 드래그 앤 드롭하는 경우, 브라우저는 파일을 열거나 이동시키는 기본 동작을 수행합니다. event.preventDefault()를 사용하여 이러한 기본 동작을 중단하고 파일을 처리하거나 업로드하는 동작을 추가할 수 있습니다.
    • 키보드 이벤트에서: 일부 키보드 이벤트에 대해서도 event.preventDefault()를 사용하여 기본 키 동작을 중단하고 사용자 정의 동작을 처리할 수 있습니다.
      요약하면, event.preventDefault()는 브라우저의 기본 동작을 중단하여 원하는 동작을 수행할 수 있게 해주는 중요한 메서드입니다. 이를 통해 웹 애플리케이션의 동작을 더욱 제어할 수 있습니다.

  • toDo가 null일 때 submit의 작동이 되지 않게 return 되는 코드를 추가하였다. 반대의 경우에만 등록되도록 하는 것이다. -> 이 부분이 if-else가 아니라 return으로 제어되는 것이 자바스크립트-ish하다.
  • 그리고 submit 후에 input 칸 안에 아무 것도 남지 않게 하는 코드를 등록하였다.


  • 그리고 나는 배열로 여러가지의 투두리스트를 입력받기 위해서, toDos와 setToDos에 대한 useState 코드를 작성하였다.
  • 평범한 자바스크립트 코드라면 이게 array니까, toDos.push를 이용하겠지만 이건 리액트의 state다.
  • 우리는 직접적으로 state를 수정할 수가 없다. 그래서 우리가 늘 변수명을 이용해 직접 지정한 set--- 함수를 이용하고 있다.

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

    • currentArray라는 매개변수를 받는 함수를 setToDos 함수의 인자로 전달합니다. 이 함수는 현재 toDos 상태 배열을 나타내며, 이전 상태를 읽어오기 위해 사용됩니다.
    • 이 함수는 현재 toDos 배열을 가져와서 새로운 배열을 생성합니다. 새로운 배열은 다음과 같이 구성됩니다.
    • toDo: 새로운 할 일 항목인 toDo를 배열의 첫 번째 요소로 추가합니다.
      ...currentArray: 스프레드 연산자(...)를 사용하여 현재 배열의 모든 요소를 새 배열에 복사합니다.
    • 최종적으로 setToDos 함수는 이 새로운 배열을 사용하여 toDos 상태를 업데이트합니다. 이로써 새로운 할 일 항목인 toDo가 현재 할 일 목록의 맨 위에 추가되게 됩니다.
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; // 함수의 작동을 막음 (kill the function)
    }

    setToDo(""); // 등록 후에 인풋 안에 남지 않게
    setToDos((currentArray) => [toDo, ...currentArray]); // 스프레드 연산자로 combine
  };

  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"
        />
        <button>Add To-do</button>
      </form>
    </div>
  );
}

export default App;

  • 이제 배열에 있는 요소들을 꺼내서 보여주기만 하면 투두리스트의 형체가 갖추어질 것이다.

To-do-list (2)

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; // 함수의 작동을 막음 (kill the function)
    }

    setToDo(""); // 등록 후에 인풋 안에 남지 않게
    setToDos((currentArray) => [toDo, ...currentArray]); // 스프레드 연산자로 combine
  };

  console.log("toDo : ", toDo);
  console.log("toDos : ", 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"
        />
        <button>Add To-do</button>
      </form>
    </div>
  );
}

  • 일단 지금까지의 앱을 살펴보자.
  • form은 그 자체로 submit 이벤트를 갖고 있는 태그라는 건 잊지 않았을 것이다.
  • 내가 지금 input 태그에 입력하고 있는 것은 onChange 함수에 의해 이벤트 변화에 따라 감지되고 있는 하나의 투두리스트 항목인 toDo이다.
  • 그리고 form 태그의 submit 이벤트가 발생함에 의해 그 toDo는 toDos라는 배열의 가장 앞 항목으로 추가되게 된다.


  • 일단 지금까지 우리는 submit을 통해 입력값을 배열에 넣는 기능을 구현했다.
  • 다시 그 배열을 잘 정리해서 보여주기 위해서 map 함수를 이용해야 하는데, toDos.map(() => ":)") 라고 적으면 배열의 아이템들이 모두 웃는 이모티콘이 되는 귀여운 상황 발생. 우리는 귀여운 기능 말고 쿨한 기능을 원하니까 뭔가 바꿔야겠지?


  • 대문자로도 바꿔버릴 수도 있고.
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; // 함수의 작동을 막음 (kill the function)
    }

    setToDo(""); // 등록 후에 인풋 안에 남지 않게
    setToDos((currentArray) => [toDo, ...currentArray]); // 스프레드 연산자로 combine
  };

  //console.log("toDo : ", toDo);
  console.log("toDos : ", 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"
        />
        <button>Add To-do</button>
      </form>

      <hr />

      <ul>
        {toDos.map((item) => (
          <li>{item}</li>
        ))}
      </ul>
    </div>
  );
}

export default App;

  • ul, li 태그를 이용하여 이렇게 작성하면 될 것이다.
  • 근데 콘솔 창의 워닝을 보면, 컴포넌트의 리스트를 렌더링할 때는 key라는 prop이 필요하다고 한다.
  • 리액트가 기본적으로 list에 있는 모든 item을 인식하기 때문에 생기는 일이다.

  • 어쨌거나 map 함수에 대해서 살펴보면 이건 사실 리액트도 아니고, 그냥 자바스크립트 차원에서 벌어지는 일이다.
  • map 함수의 두 번째 인자가 number인 index라고 한다.

  • 그래서 이렇게 수정해주었다.



<ul>
  {toDos.map((item, idx) => (
    <li key={idx}>{item}</li>
  ))}
</ul>
  • 주어진 코드는 React 컴포넌트에서 toDos 배열의 각 항목을 순회하고, 각 항목을 리스트(<ul>)의 리스트 아이템(<li>)으로 표시하는 것을 나타냅니다.
  • ul 태그는 순서 없는 목록(리스트)을 나타냅니다.
  • {toDos.map((item, idx) => ... )}: 중괄호({}) 안에 있는 표현식은 JavaScript 코드입니다. 이 부분은 toDos 배열을 map() 함수를 사용하여 순회하고 각 항목을 처리하는 부분입니다.
  • toDos.map((item, idx) => ... ): toDos 배열의 각 항목에 대해 map() 함수를 호출합니다. map() 함수는 배열의 각 요소에 대해 지정된 함수를 호출하고 새로운 배열을 반환합니다.
  • (item, idx) => (...): 화살표 함수(=>)는 map() 함수에 전달되는 함수입니다. 이 함수는 두 개의 인자, item과 idx를 받습니다.
  • item: toDos 배열의 각 항목을 나타냅니다.
  • idx: 항목의 인덱스를 나타냅니다.
  • <li key={idx}>{item}</li> : 이 부분은 각 항목을 리스트 아이템(<li>)으로 렌더링합니다.
  • key={idx}: React에서 반복되는 엘리먼트를 렌더링할 때 각 엘리먼트에 고유한 key 속성이 필요합니다. 여기서 idx (인덱스)를 사용하여 고유한 키를 생성합니다.
  • {item}: item은 toDos 배열의 각 요소로, 해당 요소의 내용을 리스트 아이템 내부에 출력합니다.
  • 최종적으로, 이 코드는 toDos 배열의 각 항목을 순회하며 각 항목을 리스트(<ul>)의 리스트 아이템(<li>)으로 렌더링합니다. 이때 각 리스트 아이템에는 고유한 key 속성이 지정되어 React가 업데이트를 효율적으로 관리할 수 있도록 합니다. 결과적으로 페이지에는 toDos 배열의 내용을 나타내는 목록이 표시됩니다.
profile
Working Abroad ...

0개의 댓글