개발새발개발/React

React - 컴포넌트 반복(map, callback, key, list, 값 추가 삭제)

birdsfoot 2024. 12. 30.

 

 

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

  • map() : 파라미터로 전달된 함수를 사용하여 배열 내 각 요소를 원하는 규칙에 따라 변환한 후 그 결과로 새로운 배열을 생성
arr.map(callback, [thisArg])

arr.map(name, index, array, [thisArg])
  • callback : 새로운 배열의 요소를 생성하는 함수. 3가지의 파라미터를 받음
    • currentValue : 현재 처리하고 있는 요소
    • index : 현재 처리하고 있는 요소의 index 값
    • array : 현재 처리하고 있는 원본 배열
  • thisArg(선택 항목) : callback 함수 내부에서 사용할 this 레퍼런스
const numbers = [1, 2, 3, 4, 5];

const processed = numbers.map(function (num) {
  return num * num;
});

console.log(processed); // [1,4,9,16,25]
const numbers = [1, 2, 3, 4, 5];

const result = numbers.map((num) => num * num);

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

 


 

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

// IterationSample.js

import React from 'react';

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

export default IterationSample;

  • App.js에 등록까지 하고 실행하면 출력은 잘 되나 console 창에 error가 발생
  • 고유의 key가 필요함

 


key

  • 컴포넌트 배열을 렌더링했을 때 어떤 원소에 변동이 있었는지 알아내기 위해 사용
  • 변화를 빠르게 감지하기 위한 고유의 값
const articleList = articles.map(article => (
    <Article
        title = {article.title}
        content = {article.content}
        key = {article.id}
    />
))

 

  • 위의 예제에는 고유 번호가 없으므로 map 함수 callback 함수의 인자인 index를 활용 
  • 다만 index를 key로 사요하면 배열이 변경될 때 효율적으로 리렌더링이 안됨 -> 아래에서 살펴보자!
// IterationSample.js

import React from 'react';

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

export default IterationSample;

 


 

동적 배열 렌더링 실습

  1. 초기 상태 설정
  2. 데이터 추가 기능 구현
  3. 데이터 제거 기능 구현

 

초기 상태 설정

  • 객체 형태로 이루어진 배열 생성
  • 고유 id 값 부여
  • name.id / name.text 로 수정
// IterationSample.js

import React, { useState } from 'react';

const IterationSample = () => {
  const [names, setNames] = useState([
    { id: 1, text: 'snowman' },
    { id: 2, text: 'ice' },
    { id: 3, text: 'wind' },
    { id: 4, text: 'snow' },
  ]);

  const [inputText, setInputText] = useState('');

  // 새로운 항목을 추가할 때 사용할 id
  const [nextId, setNextId] = useState(5);

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

export default IterationSample;

 

 

데이터 추가 기능 구현

  • 상태 안에서 배열을 변형할 때는 배열에 직접 접근해서 수정하면 안됨
  • concat, filter 등의 배열 내장 함수를 사용하여 새로운 배열을 만든 후 이를 업데이트 해주는 방식으로 해야함

 

  • 추가 버튼을 누르면 onClick 이벤트가 발생하며 값이 리스트에 추가
// IterationSample.js

import React, { useState } from 'react';

const IterationSample = () => {
  const [names, setNames] = useState([
    { id: 1, text: 'snowman' },
    { id: 2, text: 'ice' },
    { id: 3, text: 'wind' },
    { id: 4, text: 'snow' },
  ]);

  const [inputText, setInputText] = useState('');
  // 새로운 항목을 추가할 때 사용할 id
  const [nextId, setNextId] = useState(5);
  // 입력 값 저장
  const onChange = (e) => setInputText(e.target.value);


  const onClick = () => {
    const nextNames = names.concat({
      id: nextId,
      text: inputText,
    });
    setNextId(nextId + 1);
    setNames(nextNames); // names에 새 이름 추가
    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과 push

  • push : 기존 배열 자체를 변경
  • concat : 새로운 배열을 생성
  • 불변성 유지 : 원본을 최대한 유지하면서 새로운 값을 상태로 설정해야 하는 것. 고로 concat을 권장

 

 

데이터 제거 기능 구현

  • 각 항목을 더블클릭 했을 때 해당 항목이 사라지는 기능
  • 불변성을 유지하며 업데이트 해야하므로 배열의 내장함수 filter 사용
const numbers = [1, 2, 3, 4, 5, 6];
const biggerThanThree = numbers.filter((number) => number > 3);
// 결과 [4,5,6]
  • 등호를 이용해 선택, 제외(!=)등을 할 수 있음

 

// IterationSample.js

import React, { useState } from 'react';

const IterationSample = () => {
  const [names, setNames] = useState([
    { id: 1, text: 'snowman' },
    { id: 2, text: 'ice' },
    { id: 3, text: 'wind' },
    { id: 4, text: 'snow' },
  ]);

  const [inputText, setInputText] = useState('');
  // 새로운 항목을 추가할 때 사용할 id
  const [nextId, setNextId] = useState(5);
  // 입력 값 저장
  const onChange = (e) => setInputText(e.target.value);

  const onClick = () => {
    const nextNames = names.concat({
      id: nextId,
      text: inputText,
    });
    setNextId(nextId + 1);
    setNames(nextNames); // names에 새 이름 추가
    setInputText(''); // 값 비우기
  };

  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>
  ));
  return (
    <>
      <input value={inputText} onChange={onChange} />
      <button onClick={onClick}>추가</button>
      <ul>{nameList}</ul>
    </>
  );
};

export default IterationSample;

 

댓글