리액트를 다루는 기술 6장

riverkim·2022년 6월 2일
0
post-thumbnail

이 글은 책 리액트를 다루는 기술을 개인적으로 정리한 글 입니다.

컴포넌트 반복

반복적인 내용을 효율적으로 보여주고 관리하는 방법 알기

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

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

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

map함수 문법

arr.map(callback, [thisArg])

// 파라미터 정리
// - callback : 새로운 배열의 요소를 생성하는 함수
//   - currentValue : 현재 처리하고 있는 요소
//   - index : 현재 처리하고 있는 요소의 index 값
//   - array : 현재 처리하고 있는 원본 배열
// - thisArg(선택) : callback 함수 내부에서 사용할 this 레퍼런스

map함수 예제

const numbers = [1,2,3,4,5];

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

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

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

컴포넌트로 구성된 배열을 생성 가능

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

"key" prop이 없다는 경고 메시지를 표시

key

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

key 설정

key 값을 설정할 때는 map 함수의 인자로 전달되는 함수 내부에서 컴포넌트 props를 설정하듯이 설정
key 값은 언제나 유일해야 함 -> 데이터가 가진 고유값을 key 값으로 설정해야 함


// 만약 게시판의 게시물을 렌더링한다면 게시물 번호를 key 값으로 설정

const articleList = articles.map(article => (
  <Article
      title={article.title}
      writer={article.writer}
      key={article.id}
  />
);

하지만 앞서 만들었던 예제 컴포넌트에는 이런 고유 번호가 없습니다.
이때는 map 함수에 전달되는 콜백 함수의 인수인 index 값을 사용하면 됩니다.
고유한 값이 없을 때만 index 값을 key로 사용해야 합니다.
index를 key로 사용하면 배열이 변경될 때 효율적으로 리렌더링하지 못합니다.

import React from 'react';
 
const IterationSample = () => {
  const names = ['눈사람', '얼음', '눈', '바람'];
  const namesList = names.map((name, index) => <li key={index}>{name}</li>);
  return <ul>{namesList}</ul>;
};
 
export default IterationSample;

응용

고정된 배열을 렌더링하는 것이 아닌, 동적인 배열을 렌더링하는 것을 구현
index 값을 key로 사용하면 리렌더링이 비효율적 -> 어떻게 고유값을 만들수 있는가?

초기 상태 설정

import React, { useState } from 'react';
 
const IterationSample = () => {
  
  
  // useState를 사용하여 상태를 설정
  // 세 가지 상태를 사용
  // - 데이터가 담긴 배열
  // - 텍스트 입력 input 상태
  // - 데이터가 담긴 배열에 새로운 항목을 추가할 때 사용할 고유 id
  
  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 namesList = names.map(name => <li key={name.id}>{name.text}</li>);
  return <ul>{namesList}</ul>;
};
 
export default IterationSample;

데이터 추가 기능 구현하기

import React, { useState } from ‘react‘;

// 새로운 이름을 등록할 수 있는 기능 추가
// 버튼을 클릭했을 때 호출할 onClick 함수를 선언하여 버튼의 onClick 이벤트로 설정
// onClick 함수에서는 배열의 내장 함수 concat을 사용하여 새로운 항목을 추가한 배열을 만들고,
// setNames를 통해 상태를 업데이트


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, // nextId 값을 id로 설정하고
      text: inputText
    });
    setNextId(nextId + 1); // nextId 값에 1을 더해 준다.
    setNames(nextNames); // names 값을 업데이트한다.
    setInputText(); // inputText를 비운다.
  };

// onClick 함수에서 새로운 항목을 추가할 때 객체의 id 값은 nextId를 사용하도록 하고, 
// 클릭될 때마다 값이 1씩 올라가도록 구현
// 추가로 button이 클릭될 때 기존의 input 내용을 비우는 것도 구현

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;

배열에 새 항목을 추가할 때 배열의 push 함수를 사용하지 않고 concat을 사용

push 와 concat의 차이점
push 함수는 기존 배열 자체를 변경, concat은 새로운 배열을 만듦

리액트에서 상태를 업데이트할 때는 기존 상태를 그대로 두면서 새로운 값을 상태로 설정 -> 불변성 유지(컴포넌트 성능 최적화와 관련)

데이터 제거 기능 구현

각 항목을 더블클릭했을 때 해당 항목이 화면에서 사라지는 기능 구현 (불변성 유지하면서 업데이트)
불변성을 유지하면서 배열의 특정 항목을 지울 때는 배열의 내장 함수 filter를 사용

filter 함수를 사용하면 배열에서 특정 조건을 만족하는 원소들만 쉽게 분류가 가능

// numbers 배열에서 3보다 큰수만 반환
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]

을 해 주세요.

import React, { useState } from ‘react‘;

// HTML 요소를 더블클릭할 때 사용하는 이벤트 이름은 onDoubleClick
// onRemove라는 함수를 만들어서 각 li 요소에 이벤트 등록
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, // nextId 값을 id로 설정하고
      text: inputText
    });
    setNextId(nextId + 1); // nextId 값에 1을 더해 준다.
    setNames(nextNames); // names 값을 업데이트한다.
    setInputText(); // inputText를 비운다.
  };
  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>
  ));
  return (
    <>
      <input value={inputText} onChange={onChange} />
      <button onClick={onClick}>추가</button>
      <ul>{namesList}</ul>
    </>
  );
};



export default IterationSample;

정리

반복되는 데이터를 렌더링하는 방법과 이를 응용하여 유동적인 배열을 만들어 봄
컴포넌트 배열을 렌더링할 때는 key 값 설정에 항상 주의해야 함(key 값은 언제나 유일 -> key 값이 중복된다면 렌더링 과정에서 오류가 발생)

상태 안에서 배열을 변형할 때는 배열에 직접 접근하여 수정하는 것이 아니라
concat, filter 등의 배열 내장 함수를 사용하여 새로운 배열을 만든 후 이를 새로운 상태로 설정

profile
Hello!

0개의 댓글