상세 컨텐츠

본문 제목

[리액트를 다루는 기술] 6장 컴포넌트 반복

21-22/21-22 리액트 스타터 -1

by Kimpeep 2021. 11. 29. 13:00

본문

728x90

이번 장에서는 리액트 프로젝트에서 반복적인 내용을 효율적으로 보여 주고 관리하는 방법을 알아봅시다.

 

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

자바스크립트 배열 객체의 내장 함수인 map 함수를 사용하여 반복되는 컴포넌트를 렌더링 할 수 있습니다. map 함수는 파라미터로 전달된 함수를 사용하여 배열 내 각 요소를 원하는 규칙에 따라 변환한 후 그 결과로 새로운 배열을 생성합니다.

arr.map(callback, [thisArg])

callback은 새로운 배열의 요소를 생성하는 함수입니다. 파라미터는 아래 세 가지입니다.

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

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

 

map 함수를 사용하여 배열의 각 요소를 제곱해서 만든 새로운 배열

 

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

똑같은 원리로 기존 배열로 컴포넌트로 구성된 배열을 생성할 수 있습니다. map 함수에서 JSX를 작성할 때는 앞서 다룬 예처럼 DOM 요소를 작성해도 되고, 컴포넌트를 사용해도 됩니다. App 컴포넌트에서 IterationSample 컴포넌트를 불러와 렌더링 해보겠습니다.

import React, { Component } from 'react';
import IterationSample from './IterationSample';

class App extends Component {
  render() {
    return <IterationSample />;
  }
}
export default App;

웹 브라우저 화면
크롬 개발자 도구 콘솔창

웹 브라우저에 다음과 같이 나타났습니다. 하지만 크롬 개발자 도구의 콘솔을 열어보면 key가 없다는 경고 메시지가 뜹니다.

 

6-3 key

key는 컴포넌트 배열을 렌더링 했을 때 어떤 원소에 변동이 있었는지 알아내기 위해 사용합니다. key가 없을 때는 Virtual DOM을 비교하는 과정에서 리스트를 순차적으로 비교하면서 변화를 감지합니다. 하지만 key가 있다면 이 값을 사용하여 어떤 변화가 일어났는지 더욱 빠르게 알 수 있습니다.

 

key 값을 설정할 때는 map 함수의 인자로 전달되는 함수 내부에서 컴포넌트 props를 설정하듯이 설정합니다. key 값은 유일해야 하기 때문에 데이터가 가진 고윳값을 key 값으로 설정해야 합니다.

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;

고유 번호가 없을 때는 다음과 같이 map 함수에 전달되는 콜백 함수의 인수인 index 값을 사용합니다. index를 key로 사용하면 배열이 변경될 때 효율적으로 리 렌더링 하지 못하므로 고유한 값이 없을 때만 index 값을 key로 사용해야 합니다.

 

6-4 응용

지금부터는 동적인 배열을 렌더링 하는 것을 구현해 보겠습니다.

 

6-4-1 초기 상태 설정하기

useState를 사용하여 상태를 설정하겠습니다. 데이터 배열, 텍스트를 입력할 수 있는 input 상태, 데이터 배열에서 새로운 항목을 추가할 때 사용할 고유 id를 위한 상태로 총 세 가지 상태를 사용할 것입니다. 

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); //새로운 항목을 추가할 때 사용할 id

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

export default IterationSample;

이번에는 key 값을 index 대신 name.id로 값을 지정해주었습니다. 

 

6-4-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('');
  const [nextId, setNextId] = useState(5); //새로운 항목을 추가할 때 사용할 id

  const OnChange = e => setInputText(e.target.value);

  const nameList = names.map(name => <li key={name.id}>{name.text}</li>);
  return (
  <>
    <input value={inputText} onChange={onChange}/>
    <button>추가</button>
    <ul>{nameList}</ul>
  </>
  );
};

export default IterationSample;

그다음에는 버튼을 클릭했을 때 호출할 onClick 함수를 선언해보겠습니다.  onClick 함수에서는 배열의 내장 함수 concat을 사용하여 새로운 항목을 추가한 배열을 만들고 setNames를 통해 상태를 업데이트해줍니다.

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); //새로운 항목을 추가할 때 사용할 id

  const onChange = (e) => setInputText(e.target.value);
  const onClick = () => {
    const nextNames = names.concat({
      id: nextId,
      text: inputText
    });
    setNextId(nextId + 1);
    setNames(nextNames); //names  값 업데이트
    setInputText(''); //inputText 비운다
  };
  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;

배열에 새 항목을 추가할 때 배열의 push 함수 대신 concat을 사용했습니다. push 함수는 기존 배열 자체를 변경해 주는 반면, concat은 새로운 배열을 만들어 준다는 차이가 있습니다. 리액트에서 상태를 업그레이드할 때는 기존 상태를 그대로 두면서 새로운 값을 상태로 설정해야 합니다. 이를 불변성 유지라고 합니다. 불변성 유지를 해 주어야 리액트 컴포넌트의 성능을 최적화할 수 있습니다. 

 

onClick 함수에서 새로운 항목을 추가할 때 객체의 id 값은 nextId를 사용하도록 하고, 클릭될 때마다 1씩 증가하도록 구현하였습니다. 추가 버튼이 클릭될 때 기존의 input 내용이 지워지도록 구현하였습니다.

 

새로운 항목 추가

 

6-4-3 데이터 제거 기능 구현하기

각 항목을 더블클릭했을 때 해당 항목이 화면에서 지워지는 기능을 구현해 보겠습니다. 불변성을 유지하면서 배열의 특정 항목을 지울 때는 배열의 내장 함수 filter를 사용합니다. filter 함수를 사용하면 배열에서 특정 조건을 만족하는 원소들만 쉽게 분류할 수 있습니다. 

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

filter 함수의 인자에 분류하고 싶은 조건을 반환하는 함수를 넣어 주면 쉽게 분류할 수 있습니다. filter 함수를 응용하여 특정 배열에서 특정 원소만 제외시킬 수도 있습니다. 다음의 numbers 배열에서 3을 없애고 싶다면 아래와 같이 작성하면 됩니다.

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

filter 함수를 이용하여 항목 제거 기능을 구현해 봅시다.

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); //새로운 항목을 추가할 때 사용할 id

  const onChange = (e) => setInputText(e.target.value);
  const onClick = () => {
    const nextNames = names.concat({
      id: nextId,
      text: inputText,
    });
    setNextId(nextId + 1);
    setNames(nextNames); //names  값 업데이트
    setInputText(''); //inputText 비운다
  };
  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;

데이터 제거 기능

 

6-5 정리

반복되는 데이터를 렌더링하고 유동적인 배열을 다루는 방법을 배워 보았습니다. 컴포넌트 배열을 렌더링 할 때는 key 값 설정에 항상 주의해야 합니다. 중복되는 key 값은 렌더링 과정에서 오류를 발생하기 때문에 key 값은 언제나 유일해야 합니다. 상태 안에서 배열을 변경할 때는 배열에 직접 접근하여 수정하는 것이 아니라 concat, filter 등의 배열 내장 함수를 사용하여 새로운 배열을 만든 후 이를 새로운 상태로 설정해 주어야 합니다.

 

 

6장 Quiz

1. 자바스크립트 배열 객체의 내장 함수이며, 반복되는 컴포넌트를 렌더링 할 수 있는 함수는?

2. key 값은 언제나 유일해야 한다. (O/X)

3.  push 함수는 새로운 배열을 만들어 주는 반면, concat은 기존 배열 자체를 변경해 준다는 차이가 있다. (O/X)

4. 리액트에서 상태를 업그레이드할 때는 기존 상태를 그대로 두면서 새로운 값을 상태로 설정해야 하는데 이를 ooo oo라고 합니다.

 

 

더보기

Quiz 답

1. map 함수

2. O

3. X

4. 불변성 유지

 

 

 

 

 


Corner React Starter #1
Editor dori

728x90

관련글 더보기