업데이트:

태그:

카테고리:



Velopert



컴포넌트 반복

화면에 반복적인 요소를 그릴때, 각 요소를 그려야하면 비효율적이다.
반복되는 내용을 컴포넌트로 만들어 map함수를 적용하자.



자바스크립트의 map()함수

JS 배열객체에 map함수를 적용하여 반복되는 컴포넌트를 렌더링할 수 있다.

map함수의 문법

array.map(callback, [thisArg]) callback => 새로운 배열의 요소를 생성하는 콜백함수, 파라미터는

  • currentValue : 현재 처리하고 있는 요소
  • index : 현재 처리하고 있는 요소의 index값
  • array : 현재 처리하고 있는 원본배열

this.arg => callback함수 내부에서 사용할 this 레퍼런스, 선택사항



map으로 데이터배열을 컴포넌트 배열로 변환

import React from "react";

const IterationSample = () => {
  const names = ["", "크리스마스", "얼음"];
  const nameList = names.map((name) => <li>{name}</li>);

  return <ul>{nameList}</ul>;
};

export default IterationSample;

names의 각 요소가 nameList에 li태그로 감싸져 JSX코드로된 배열을 새로 생성한 후, nameList에 담는다.



key prop

위 코드를 그대로 렌더링하면 key prop이 없다는 경고 메세지가 표시된다.

index.js:1 Warning: Each child in a list should have a unique "key" prop.

Check the render method of `IterationSample`. See https://reactjs.org/link/warning-keys for more information.
    at li
    at IterationSample
    at div
    at App (http://localhost:3000/static/js/main.chunk.js:47:1)

위 코드를 그대로 렌더링하면 key prop이 없다는 경고 메세지가 표시된다.



key

리액트가 key를 필요로하는 이유는 컴포넌트 배열을 렌더링할때 어떤 원소가 변동이 되었는지 빠르게 찾아내기 위해 사용한다.

<ul>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

<ul>
  <li>Connecticut</li>
  <li>Duke</li>
  <li>Villanova</li>
</ul>

이전 Virtual DOM과 비교해, 사람이 보기에는 맨 앞에 li가 하나만 추가되었음에도
리액트는 이를 ul안의 모든 요소가 바뀐것으로 인지하고 다시 렌더링한다 -> 비효율발생

따라서 key를 부여함으로서 더 효율적인 렌더링이 가능하다



key설정

key를 설정할때는 prop설정하듯 해야한다.
이 키값은 전역공간이 아닌 형제사이에서만 유일하면된다(li끼리만 안겹치면됨)

이 key값으로는 보통 id와같은 고유번호를 부여하는게 좋은데, 마땅한게 없다면 index값을 사용하면된다.

index를 key로사용할때 주의할점은 배열이 변경되면 효율적 리렌더링이 불가능하다는 것이다.



응용

초기상태 -> 데이터 추가기능 -> 데이터 제거기능

초기상태설정

useState()으로 IterationSample변경

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("");
  const [nextId, setNextId] = useState(5);

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

export default IterationSample;



데이터 추가기능

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("");
  const [nextId, setNextId] = useState(5);
  const onChange = (e) => {
    setInputText(e.target.value);
  };

  const onClickButton = () => {
    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 type="text" value={inputText} onChange={onChange}></input>
      <button onClick={onClickButton}>확인</button>
      <ul>{nameList}</ul>
    </>
  );
};

export default IterationSample;

Input과 확인 Button 추가됨

onChange -> Input의 text state를 유지 onClickButton -> 눌리면 현재 text state에 들어있는 내용을 nextID를 가진채로 추가.

concat함수로 불변성을 유지한다.(원본유지)



데이터 제거기능

filter함수

데이터를 추가할때 불변성을 유지하기 위해 concat함수를 이용했었다.
제거할때 불변성을 유지하기위해선 filter함수를 사용해야한다.

arr.filter(원소 => 표현식) 각 원소에 대해 표현식을 만족하는 원소로 배열을 새로 만들어 리턴한다.



filter함수 적용

numbers = [1, 2, 3, 4, 5];
const biggerthanthree = numbers.filter((number) => number > 3);
const withoutthree = numbers.filter((number) => number != 3);
const nameList = names.map((name) => (
    <li key={name.id} onDoubleClick={() => onRemove(name.id)}>
      {name.text}
    </li>

key값으로 id가 li에 부여되고있는데, 해당 id를 가진 태그가 더블클릭되면 그 id를 인자로 받는 onRemove함수를 호출한다.

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

onRemove함수는 names state에 대해 인자로받은 id를 제외한 리스트를 새로 생성하고,
state를 업데이트한다.

댓글남기기