컴포넌트 반복(배열과 맵)

ho_vi·2023년 9월 19일

React

목록 보기
7/19
post-thumbnail

리액트에서 배열과 맵은 컴포넌트 렌더링에서 매우 중요한 역할을 합니다. 이들은 데이터를 다룰 때 많이 사용되는 자바스크립트의 데이터 구조입니다.

배열은 순서가 있는 데이터의 집합으로, 각 요소는 인덱스를 가지고 있습니다. 맵은 키와 값을 가지는 구조로, 키와 값을 쌍으로 이루어져 있으며 키는 중복되지 않습니다.

고정 배열 렌더링 하기

비효율적이지만 배열 그대로를 코드를 작성하는 방법 (무식한 방법)

function UserList() {
    const users = [
        {
            id : 100,
            userName : "천지훈",
            email : "1000won@gmail.com"
        },
        {
            id : 200,
            userName : "백마리",
            email : "2000won@gmial.com"
        },
        {
            id : 300,
            userName : "서민혁",
            email : "3000won@gmail.com"
        }
    ];
    return (
        <div>
            <div>
                <b>{users[0].userName}</b> <span>{users[0].email}</span>
            </div>
            <div>
                <b>{users[1].userName}</b> <span>{users[1].email}</span>
            </div>
            <div>
                <b>{users[2].userName}</b> <span>{users[2].email}</span>
            </div>
        </div>

    );
}
export default UserList;

컴포넌트를 만들고 props로 전달하는 방법

  • User컴포넌트는 사용자 이름과 이메일을 화면에 보여주는 컴포넌트 입니다.
  • UserList컴포넌트는 여러 개의 User컴포넌트를 렌더링하는 컴포넌트입니다.
function User(props) {
    return (
        <div>
            <b>{props.user.userName}</b> <span>{props.user.email}</span>
        </div>
    );

}

function UserList() {
    const users = [
        {
            id : 100,
            userName : "천지훈",
            email : "1000won@gmail.com"
        },
        {
            id : 200,
            userName : "백마리",
            email : "2000won@gmial.com"
        },
        {
            id : 300,
            userName : "서민혁",
            email : "3000won@gmail.com"
        }
    ];
    return (
        <div>
           <User user={users[0]} />
           <User user={users[1]} />
           <User user={users[2]} />
        </div>

    );
}
export default UserList;

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

자바스크립트 배열의 객체의 내장 함수인 map 함수를 사용하여 반복되는 컴포넌트를 렌더링 할 수 있습니다.

map 함수는 파라미터로 전달된 함수를 사용해서 배열 내 각 요소를 원하는 규칙에 따라 변환한 후 그 결과로 새로운 배열을 생성 합니다.

배열의 요소를 기반으로 동적으로 컴포넌트를 생성하고, 이를 렌더링 합니다.

사용 예 (각 요소에 3을 곱하기)

let arr = [3, 4, 5, 6];//
let newArr = arr.map(e => e * 3);

객체 배열에서 map()을 사용하는 방법 (컴포넌트 렌더링 포함)

배열의 내용을 map을 이용해 출력하는 방법(1)

const numbers = [1, 2, 3, 4, 5];
const listItems = numbers.map((e) => <li>{e}</li>);
return (
		<ul>{listItems}</ul>
	);

배열의 내용을 map을 이용해 출력하는 방법(2)

const MapTest = () => {
    let names = [
        {firstName : "지훈", lastName : "천"},
        {firstName : "마리", lastName : "백"},
        {firstName : "민혁", lastName : "서"}
    ];
    let fullNames = names.map(name => <div>{name.lastName}{name.firstName}</div>);
    return fullNames;
}
export default MapTest;
import './App.css';
import MapTest from './MapTest.js';

const App = () => {
  return < MapTest />
};

export default App;

Map에 키가 없는 경우

아래와 같이 코드를 작성하면 원하는결과가 렌더링 되지만, key prop이 없다는 경고 메시지가 출력 됩니다.

const IterationSample = () => {
    const seasons = ["새로운 봄", "활기찬 여름", "풍성한 가을", "새하얀 겨울"];
    const nameList = seasons.map(season => <li>{season}</li>);
    return <ul>{nameList}</ul>;
}
export default IterationSample;
import './App.css';
import IterationSample from './IterationSample.js';

const App = () => {
  return < IterationSample />
};

export default App;

Key

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

React의 Virtual DOM을 비교하는 과정에서 Key가 있다면 이 값을 사용하여 어떤 변화가 일어났는지 빠르게 알아 냅니다.

const IterationSample = () => {
    const seasons = ["새로운 봄", "활기찬 여름", "풍성한 가을", "새하얀 겨울"];
    const nameList = seasons.map((season, index) => <li key={index}>{season}</li>);
    return <ul>{nameList}</ul>;
}
export default IterationSample;

useState와 함께 사용하여 데이터 추가 기능 구현

  • onClick 함수에서는 배열의 내장 함수 concat을 사용하여 새로운 항목을 추가한 배열을 만들고, setNames를 통해 상태를 업데이트 해줍니다.
  • 배열에 새 항목을 추가 할 때 배열의 push 함수를 사용하지 않고 concat 함수를 사용한 이유는 push 함수는 기존 배열 자체를 변경해 주는 반면, concat은 새로운 배열을 만들어 준다는 차이점이 있습니다.
  • 리액트에서 상태를 업데이트 할 때는 기존의 상태를 그대로 두면서 새로운 값을 상태로 설정해야 합니다. 이를 불변성유지하고 하며, 불변성을 유지를 해주어야 나중에 이랙트 컴포넌트의 성능을 최적화 할 수 있습니다.
  • onClick 함수에서 새로운 항목을 추가할 때 객체의 id값은 nextId를 사용하도록 하고, 클릭될 때 마다 값이 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("");
    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); //nextId 값에 1을 더해준다
        setNames(nextNames);
        setInputText(''); // inputText를 비운다.
    };

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

    return (
        <>
            <input value={inputText} onChange={onChange} />
            <button onClick={onClick}>추가</button>
            <ul>{namesList}</ul>
        </>
    );    
};
export default IterationSample;

데이터 제거 기능 구현

filter 함수를 사용하면 배열에서 특정 조건을 만족하는 원소들만 쉽게 분류할 수 있습니다.

const numbers = [1,2,3,4,5];
const withoutThree = numbers.filter(number => number !== 3);
// 결과 [1,2,4,5,6]

응용

  • 고정된 배열을 렌더링하는 것이 아닌, 동적인 배열을 렌더링하는 것을 구현
  • 배열을 설정할 때, 단순한 문자열이 아닌 객체 형태의 배열 생성
  • 객체에는 문자열과 고유 id값
  • onClick 함수에서 배열의 내장 함수 concat을 사용하여 새로운 항목을 추가한 배열을 만들고, setNames를 통해 상태를 업데이트
  • 배열에 새 항목을 추가 할 때 배열의 push 함수를 사용하지 않고 concat 함수를 사용한 이유는 push 함수는 기존 배열 자체를 변경해 주는 반면, concat은 새로운 배열을 만들어 준다는 차이점이 있습니다.
  • 리액트에서 상태를 업데이트 할 때는 기존 상태를 그대로 두면서 새로운 상태값을 설정해야 합니다. 이를 불변성 유지라고 하는데 불변성 유지를 해야 리액트 컴포넌트의 성능을 최적화 할 수 있습니다.
  • HTML 요소를 더블클릭할 때 사용하는 이벤트 이름은 onDoubleClick 입니다. onRemove라는 함수를 만들어 li 요소에 이벤트 등록

IterationSample.js

import React, { useState } from "react";
import './App.css';
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 onClick = () => {
        const nextNames = names.concat({
            id: nextId,
            text: inputText
        });
        console.log(nextNames);
        setNextId(nextId + 1);
        setNames(nextNames);
        setInputText('');
    };

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

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

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

    return (
        <>
            <p className="title-name">to do List </p>
            <p>삭제는 해당 항목을 더블클릭 하세요.</p>
            <input value={inputText} onChange={onChange} />
            <button onClick={onClick}>추가</button>
            <ul>{namesList}</ul>
        </>
    );    
};
export default IterationSample;

CSS

.title-name {
  color: royalblue;
  font-size: 2em;
  background-color: orange;
}
profile
FE 개발자🌱

0개의 댓글