본문 바로가기

프론트엔드(Front-End)/React

[REACT] 컴포넌트 요소의 반복(map, filter)

컴포넌트의 반복

  • 리액트에서 동일한 html 요소를 생성하는 방법은 Vanila JavaScript를 사용합니다.
  • 자바스크립트 문법에는 map이라는 메서드를 통해 배열을 복사하거나 새롭게 계산하여 생성할 수 있습니다.

자바스크립트 map

const array1 = [1, 4, 9, 16];

// Pass a function to map
const map1 = array1.map(x => x * 2);

console.log(map1);
// expected output: Array [2, 8, 18, 32]

react에서도 반복되는 element를 만들 때에는 map 함수와 JSX를 사용하여 생성합니다.

 

map 함수의 문법은 다음과 같습니다.

arr.map(callback, [this.Arg])

여기서 각각의 파라미터는 다음과 같습니다.

callback : 새로운 배열의 요소를 생성하는 함수로 내부 파라미터는 세 가지로 구성됩니다.

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

thisArg(선택항목) : callback 함수 내부에서 사용할 this 레퍼런스

 

💡 여기서 잠깐!

  • 리액트에서 map 함수를 통해 Element를 생성할 때에는 key 값을 요구합니다.
  • 이 값은 html에서 id 속성 값의 역할을 하는 값으로 이 값을 assign 해주지 않아도 반복되는 element 생성은 가능합니다만, 콘솔 창에서 아래와 같은 오류를 출력합니다.

 

  • 자바 스크립트 map 함수의 callback 함수에서 매개변수로 index가 있었습니다.
  • 이 index를 반복되는 element 의 key 값으로 assign 해준다면 위의 오류는 사라집니다.
  • 하지만, 리액트에서 map 함수로 element를 생성 할 때의 key의 역할은 id와 같다고 하였습니다. html 요소에서 id 값도 실제로 중첩을 금지하거나 잘못 쓰면 Java와 같은 프로그래밍 언어의 컴파일 오류처럼 바로 잡아내는 것이 아니라 일단 실행은 되는데 작동이 안되는 식으로 오류가 발생합니다.
  • 리액트에서 요소를 반복 생성할 때 사용하는 key 속성도 마찬가지로 중첩이 되는 것을 강제로 막지는 않겠지만, 중첩이 되면 중첩되는 것들을 구분하는 데에 시간을 소모할 것이므로 전체적인 성능이 하락하는 것입니다.

 

리액트에서 map 메서드와 JSX를 사용해 요소를 생성

import "../asset/mapClassComp01.css"

import { Fragment } from "react";

const MapFuncComp01 = () => {
  const names = ['봄', '여름', '가을', '겨울'];
  const nameList = names.map((name, index) => <li key={index}>{name}</li>);
{/* 리액트에서 인덱스를 키 값으로 사용하면 리렌더링할 때 효율적이지 못해서 좋지 않다. 
자바스크립트에서는 아이디가 겹치면 안되지만, 문법적으로 아이디가 겹치는 것을 막진 않는다. 
자바 IDE에서 컴파일 오류 처럼 코드 소스 상에서 바로 오류가 발생하진 않는다. 
콘솔에 오류가 찍히거나 기능이 정상수행 안되는 정도이다. 
이러한 특징 때문에 index를 아이디로 삼으면 리액트가 요소를 찾을 때 비효율이 발생할 수 있기 때문에 비권장한다
*/}
  
  return (
    <>
      <div className="comp func-comp map-comp">
        <ul>
          {nameList}
        </ul>
      </div>
    </>
  )
}

export default MapFuncComp01;

 

실제 렌더링 된 화면

 

map 함수를 사용하여 요소를 반복할 때에는 아래와 같이 코드를 작성하는 것이 권장됩니다.

개발자가 요소마다 고유성을 확보할 수 있는 값을 할당해주는 것이 좋습니다.

 

map함수를 통해 요소를 동적으로 생성하고 삭제하는 페이지 생성

import { Fragment, useState } from "react";

const MapFuncComp02 = () => {
  const [names, setNames] = useState([
    { id: 1, name: '봄' },
    { id: 2, name: '여름' },
    { id: 3, name: '가을' },
    { id: 4, name: '겨울' }
  ]);
  const [inputText, setInputText] = useState('');
  const [nextId, setNextId] = useState(names.length);
  
  const handleOnChange = e => setInputText(e.target.value);
  const handleOnClick = () => {
    const nextNames = names.concat({
      id: nextId,
      name: inputText
    });
    setNextId(nextId + 1);
    setNames(nextNames);
    setInputText('');
  }
  const handleOnKeyDown = (e) => {
    if (e.key == 'Enter') {
      handleOnClick();
    }
  }

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

  const nameList = names.map(item => <li key={item.id}>{item.name} <span onClick={()=>{doRemove(item.id)}}>x</span></li>);

  return (
    <>
      <div className="comp func-comp map-comp">
        <input
          value={inputText}
          onChange={handleOnChange}
          onKeyDown={handleOnKeyDown} />
        <button onClick={handleOnClick}>추가</button>
        <ul>
          {nameList}
        </ul>
      </div>
    </>
  )
}

export default MapFuncComp02;

실제 렌더링 된 화면

 

실제 요소 추가와 삭제

'프론트엔드(Front-End) > React' 카테고리의 다른 글

[REACT] 리액트와 훅(HOOK)  (0) 2023.01.08
[REACT] 리액트의 라이프사이클(LifeCycle)  (0) 2023.01.07
[REACT] 리액트의 ref  (0) 2023.01.05
[REACT] 리액트와 EVENT  (0) 2023.01.04
[REACT] 리액트의 STATE  (0) 2023.01.03