6장 - 컴포넌트 반복

sh·2022년 8월 3일
0

map() 함수

문법

arr.map(callback, [thisArg])

  • callback: 새로운 배열의 요소를 생성하는 함수
    • currentValue: 현재 처리하고 있는 요소
    • index: 현재 처리하고 있는 요소의 index값
    • array: 현재 처리하고 있는 원본 매열
  • thisArg(선택): callback 함수 내부에서 사용할 this 레퍼런스

데이터 배열을 컴포넌트 배열로 변환하기

import React from "react";

const IterationSample = () => {
  const names = ["눈사람", "얼음", "눈", "바람"];
  const nameList = names.map((name) => <li>{name}</li>);
  return <ul>{nameList}</ul>;
};

export default IterationSample;

key


위 코드의 실행결과 콘솔에 key가 없다는 경고 메시지 출력된다.

key는 컴포넌트 배열을 렌더링했을 때 어떤 원소에 변동이 있었는지 알아내려고 사용한다.

key가 없을 때는 Virtual DOM을 비교하는 과정에서 리스트를 순차적으로 비교하면서 변화를 감지하지만 key가 있다면 어떤 변화가 일어났는지 더욱 빠르게 알아낼 수 있다.

key설정

key값은 언제나 유일해야 한다.

const articleList = articles.map(article => (
  <Article
  	title={article.title}
    writer={article.writer}
	key={article.id}
  />
);

만약 고유한 값이 없다면 index 값을 사용한다. 하지만 index를 key로 사용하면 배열이 변경될 때 효율적으로 리렌더링하지 못한다.


응용

1. 초기 상태 설정하기

import React, { useState } from "react";

const IterationSample = () => {
  const [names, setNames] = useState([
    // 객체 형태로 이루어진 데이터 배열
    { id: 1, text: "눈사람" },
    { id: 2, text: "얼음" },
    { id: 3, text: "눈" },
    { id: 4, text: "바람" },
  ]);
  const [inputText, setInputText] = useState(""); //input의 상태
  const [nextId, setNextId] = useState(5); // 새로운 항목을 추가할 때 사용할 고유 id

  const nameList = names.map((name) => <li key={name.id}>{name.text}</li>);
  return <ul>{nameList}</ul>;
};

export default IterationSample;

2. 데이터 추가 기능 구현하기

import React, { useState } from "react";

const IterationSample = () => {
  const [names, setNames] = useState([
    // 객체 형태로 이루어진 데이터 배열
    { id: 1, text: "눈사람" },
    { id: 2, text: "얼음" },
    { id: 3, text: "눈" },
    { id: 4, text: "바람" },
  ]);
  const [inputText, setInputText] = useState(""); //input의 상태
  const [nextId, setNextId] = useState(5); // 새로운 항목을 추가할 때 사용할 고유 id

  const onChange = (e) => setInputText(e.target.value);
  const onClick = () => {
    const nextNames = names.concat({
      id: nextId,
      text: inputText,
    });
    setNextId(nextId + 1);
    setNames(nextNames);
    setInputText("");
  };
  const nameList = names.map((name) => <li key={name.id}>{name.text}</li>);

  return (
    <>
      <input value={inputText} onChange={onChange} />
      <button onClick={onClick}>추가</button>
      <ul>{nameList}</ul>
    </>
  );
};

export default IterationSample;

버튼을 클릭할 때 배열의 내장 함수 concat을 사용하여 새로운 항목을 추가한 배열을 만들고 setNames를 통해 상태를 업데이트해준다.

push vs concat

push: 기존 배열 자체를 변경
concat: 새로운 배열 생성

리액트에서 상태를 업데이트할 때는 기존 상태를 그대로 두면서 새로운 값을 상태로 설정해야 한다. ➡️ 불변성 유지

3. 데이터 제거 기능 구현하기

각 항목을 더블클릭했을 때(onDoubleClick) 해당 항목이 화면에서 사라지는 기능 구현

위에서의 concat과 마찬가지로 불변성을 유지하면서 업데이트해 주어야 한다. 불변성을 유지하면서 배열의 특정 항목을 지울 때 filter 함수 사용

onRemove함수를 생성해 각 li 요소에 이벤트를 등록한다.

 const onRemove = (id) => {
    const nextNames = names.filter((name) => name.id !== id);
    setNames(nextNames);
  };

  const nameList = names.map((name) => (
    <li key={name.id} onDoubleClick={() => onRemove(name.id)}>
      {name.text}
    </li>
  ));

정리

  • 컴포넌트 배열을 렌더링할 때는 key값 설정에 항상 주의해야 한다.
  • 상태 안에서 배열을 변형할 때는 배열에 직접 접근하여 수정하는 것이 아닌 concat, filter 등의 배열 내장 함수를 사용해 새로운 배열을 만든 후 새로운 상태로 설정한다.

0개의 댓글