[React] 7. 반복되는 컴포넌트

🏃Dekay (JuniorDeveloper)·2021년 9월 24일
0

React

목록 보기
7/13
post-thumbnail

1. 반복되는 컴포넌트 ✔

  • 웹 애플리케이션을 만들다 보면 아래와 같이 반복되는 코드가 있다.
//IterationSample.js
<ul>
  <li>박대경</li>
  <li>학생</li>
  <li>대학생</li>
  <li>성인</li>
</ul>
  • 위 처럼 코드가 더 복잡하거나 코드양이 더욱 늘어나게 되면 파일 용량도 증가하게 되는데 이것은 낭비이다.
  • 이러한 문제점을 리액트 프로젝트에서 효율적으로 보여주고 관리할 수 있다.

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

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

1.1.1 문법

arr.map(callback, [thisArg])
  • callback: 새로운 배열의 요소를 생성하는 함수, 파라미터는 다음과 같다.
    • currentValue: 현재 처리하고 있는 요소
    • index: 현재 처리하고 있는 요소의 index 값
    • array: 현재 처리하고 있는 배열의 원본
  • thisArg(선택항목): callback 함수 내부에서 사용할 this 레퍼런스

1.1.2 map 함수 예제✏

  • map 함수를 사용하여 배열 [1, 2, 3, 4, 5]의 각 요소를 제곱해서 새로운 배열을 생성해보자.
var numbers = [1, 2, 3, 4, 5];

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

// 👉 결과: [1, 4, 9, 16, 25]

// 위의 코드를 ES6 문법으로 작성
const numbers = [1, 2, 3, 4, 5];
const result = numbers.map(num => num * num);

// 👉 결과: [1, 4, 9, 16, 25]

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

  • 1.1.2 절과 같이 똑같은 원리로 기존 배열로 컴포넌트로 구성된 배열을 생성할 수 있다.

1.2.1 컴포넌트 수정하기

  • 1 절에서 만들었던 IterationSample 컴포넌트를 다음과 같이 수정했다.
//IterationSample.js
const IterationSample = () => {
    const names = ['박대경', '학생', '대학생', '성인'];
    const nameList = names.map(name => <li>{name}</li>);
    return <ul>{nameList}</ul>;
};
  • 그 후, App 컴포넌트에서 IterationSample 컴포넌트를 불러와 렌더링하면 아래와 같이 렌더링된다.

  • 하지만, 개발자 도구의 콘솔을 보면 경고메세지가 출력된다.
  • Warning: Each child in a list should have a unique "key" prop.
    즉, key prop가 없다는 경고 메시지다.

1.3 key

  • 리액트에서 key컴포넌트 배열을 렌더링했을 때 어떤 원소에 변동이 있는지 알기 위해서 사용한다.
    즉, 원소를 생성, 제거, 수정이 가능하다.
  • 하지만, key가 없을 때는 Virtual DOM을 비교하는 과정에서 리스트를 순차적으로 비교하면서 변화를 알아낸다.
  • 쉽게 정리하면 key가 있을 경우 key를 사용하여 어떤 변화가 일어나는지 빠르게 알 수 있다.

1.3.1 key 설정

  • key 값을 설정할 때는 map 함수의 인자로 전달되는 함수 내부에서 컴포넌트 props를 설정하듯이 설정하면 된다.
    주의❗❗ key 값은 언제나 유일해야함
  • 1.2 절의 예제 컴포넌트는 고유 번호가 없기 때문에 map 함수에 전달되는 콜백 함수인 index 값을 사용하면 된다.
//IterationSameple.js
const IterationSample = () => {
    const names = ['박대경', '학생', '대학생', '성인'];
    const nameList = names.map((name, index) => <li key={index}>{name}</li>);
    return <ul>{nameList}</ul>;
};
  • 위와 같이 코드를 작성하면 개발자 도구 콘솔에 더 이상 경고 메시지는 출력되지 않는다.
  • 여기서 또 주의해야할 점이 있다.
    고유한 값이 없을 때만 index 값을 key로 사용해야 한다.
    • 왜?🧐 배열이 변경될 때 리렌더링 과정이 효율적이지 못하기 때문❗

1.4 다른 예제

  • 고정된 배열을 렌더링하는 것이 아닌, 동적인 배열을 렌더링하는 예제와, key 값이 없을 때 어떻게 key 값을 생성할 수 있는지 코드를 작성해 보자.

1.4.1 컴포넌트 생성

  • IterationSample 컴포넌트 에서 useState를 사용하여 상태를 설정하여 코드를 작성했다.
  • 총 세 가지 상태를 사용한다.
    데이터 배열, 텍스트 입력이 가능한 input, 고유 값 생성
//IterationSample.js
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, // nextId 값을 id로 설정
            text: inputText
        });
        setNextId(nextId + 1); // nextId 값에 +1
        setNames(nextNames); // names 값 업데이트
        setInputText(''); // inputText 값 비우기.
    };

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

  • 배열에 새 항목을 추가할 때 배열의 push 함수를 사용하지 않고 concat을 사용했다.
  • 그 이유는 push 함수는 기존 배열 자체를 변경하지만 concat은 새로운 배열을 만들어 준다는 차이점이 있다.
  • 리액트에서 상태 업데이트할 때는 기존 상태를 그대로 두면서 새로운 값을 상태로 설정해야한다. ❗❗
  • 이와 반대로 데이터를 제거할 때는 filter함수를 사용하여 구현하면 될것 같다.

end

profile
Believe you can & you're half way there 🙏

0개의 댓글