글 작성자: bbangson
반응형

배열 렌더링하기 

리액트에서 배열을 렌더링하는 방법을 알아보겠습니다. 

 

sample.js

const users = [
  {
    id: 1,
    username: 'velopert',
    email: 'public.velopert@gmail.com'
  },
  {
    id: 2,
    username: 'tester',
    email: 'tester@example.com'
  },
  {
    id: 3,
    username: 'liz',
    email: 'liz@example.com'
  }
];

만약에 이 내용을 컴포넌트로 렌더링한다면 가장 기본적인 방법으로 비효율적이지만, 그냥 그대로 코드를 작성하는 것 입니다.

 

 

UserList.js

import React from 'react';

function User({ user }) {
  return (
    <div>
      <b>{user.username}</b> <span>({user.email})</span>
    </div>
  );
}

function UserList() {
  const users = [
    {
      id: 1,
      username: 'velopert',
      email: 'public.velopert@gmail.com'
    },
    {
      id: 2,
      username: 'tester',
      email: 'tester@example.com'
    },
    {
      id: 3,
      username: 'liz',
      email: 'liz@example.com'
    }
  ];

  return (
    <div>
      {users.map(user => (
        <User user={user} key={user.id} />
      ))}
    </div>
  );
}

export default UserList;

 

결과화면

결과 화면

배열이 고정적이라면 상관없지만, 배열의 인덱스를 하나하나 조회해가면서 렌더링하는 방법은 동적인 배열을 렌더링하지 못합니다.

 

동적인 배열을 렌더링해야 할 때에는 자바스크립트 배열의 내장함수 map()을 사용합니다.

 

 

map() 함수는 배열안에 있는 각 원소를 변환하여 새로운 배열을 만들어줍니다. 리액트에서 동적인 배열을 렌더링해야 할 때는 이 함수를 사용하여 일반 데이터 배열을 리액트 엘리먼트로 이루어진 배열로 변환해주면 됩니다.

 

 

<div>
  {users.map((user, index) => (
    <User user={user} key={index} />
  ))}
</div>

리액트에서 배열을 렌더링 할 때에는 key라는 props를 설정해야합니다. key값은 각 원소들마다 가지고 있는 고유값으로 설정을 해야합니다. 지금의 경우엔 id가 고유값입니다.

 

만약 배열 안의 원소가 가지고 있는 고유한 값이 없다면 map() 함수를 사용할 때 설정하는 콜백함수의 두 번째 파라미터 indexkey로 사용하면 됩니다. 

<div>
  {users.map((user, index) => (
    <User user={user} key={index} />
  ))}
</div>

위처럼 사용하면 됩니다. 

 

하지만 indexkey를 사용하게 되면 브라우저 상에서 경고창은 안뜨게 할 수 있지만, 성능적으로는 좋지 않습니다.

각 객체에 id 같은 고유의 값으로 key를 선언해주는 것이 성능적인 면에서 훨씬 좋습니다.

 

 

 

useRef로 컴포넌트 안의 변수 만들기

컴포넌트에서 특정 DOM을 선택할 때, ref를 사용합니다.

 

함수형 컴포넌트에서 이를 설정할 때, useRef를 사용하여 설정할 수 있습니다. 

 

useRef Hook은 DOM을 선택하는 용도 외에도, 다른 용도가 한가지 더 있습니다.

바로, 컴포넌트 안에서 조회 및 수정할 수 있는 변수를 관리하는 것입니다. 

 

useRef 로 관리하는 변수는 값이 바뀐다고 해서 컴포넌트가 리렌더링되지 않습니다. 리액트 컴포넌트에서의 상태는 상태를 바꾸는 함수를 호출하고 나서 그 다음 렌더링 이후로 업데이트 된 상태를 조회 할 수 있는 반면, useRef 로 관리하고 있는 변수는 설정 후 바로 조회 할 수 있습니다.

 

이 변수를 사용하여 대표적으로 다음과 같은 값을 관리할 수 있습니다. 

 

- setTimeout, setInterval을 통해서 만들어진 id 

- 외부 라이브러리를 사용하여 생성된 인스턴스

- Scroll 위치

 

App 컴포넌트에서 useRef를 사용하여 변수를 관리해보겠습니다.

용도는 앞으로 배열에 새 항목을 추가할건데, 새 항목에서 사용 할 고유 id를 관리하는 용도입니다. 

 

useRef 를 사용하여 변수를 관리하기 전에 해야 할 작업이 있습니다.

 

현재는 UserList 컴포넌트 내부에서 배열을 직접 선언해서 사용했습니다.

이렇게 UserList 에서 선언해서 사용하는 대신에, 이 배열을 App 에서 선언하고 UserList 에게 props 로 전달을 해주겠습니다.

 

 

UserList.js

import React from 'react';

function User({ user }) {
  return (
    <div>
      <b>{user.username}</b> <span>({user.email})</span>
    </div>
  );
}

function UserList({ users }) {
  return (
    <div>
      {users.map(user => (
        <User user={user} key={user.id} />
      ))}
    </div>
  );
}

export default UserList;

이제 App.js에서 useRef()를 사용하여 nextId라는 변수를 만들어보겠습니다.

 

 

App.js

import React, { useRef } from 'react';
import UserList from './UserList';

function App() {
  const users = [
    {
      id: 1,
      username: 'velopert',
      email: 'public.velopert@gmail.com'
    },
    {
      id: 2,
      username: 'tester',
      email: 'tester@example.com'
    },
    {
      id: 3,
      username: 'liz',
      email: 'liz@example.com'
    }
  ];

  const nextId = useRef(4);
  const onCreate = () => {
    // 나중에 구현 할 배열에 항목 추가하는 로직
    // ...

    nextId.current += 1;
  };
  return <UserList users={users} />;
}

export default App;

다음 만들어질 id가 4이기 때문에 useRef의 초기값은 4입니다.

useRef() 를 사용 할 때 파라미터를 넣어주면, 이 값이 .current 값의 기본값이 됩니다.

 

그리고 이 값을 수정 할때에는 .current 값을 수정하면 되고 조회 할 때에는 .current 를 조회하면 됩니다.

 

굳이 useRef()를 사용해서 변수를 만든 이유는 변수의 값이 수정되도 리렌더링이 되지 않기 때문입니다. 물론 useState()등을 이용하여 변수를 관리할 수 있지만, 굳이 다시 렌더링 되는 것을 방지하고자 할 때는 useRef()를 사용하면 됩니다. 

 

useRef()는 특정 DOM을 선택하고자 할 때 사용할 수도 있지만, 변수를 리렌더링 되도 계속 기억하고자 할 때도 사용됩니다.

 

 

배열에 항목 추가하기

배열에 새로운 항목을 추가하는 방법을 알아보겠습니다. 

 

CreateUser 컴포넌트를 생성하겠습니다.

CreateUser.js

import React from 'react';

function CreateUser({ username, email, onChange, onCreate }) {
  return (
    <div>
      <input
        name="username"
        placeholder="계정명"
        onChange={onChange}
        value={username}
      />
      <input
        name="email"
        placeholder="이메일"
        onChange={onChange}
        value={email}
      />
      <button onClick={onCreate}>등록</button>
    </div>
  );
}

export default CreateUser;

 

App.js

import React, { useRef, useState } from 'react';
import UserList from './UserList';
import CreateUser from './CreateUser';

function App() {

  // 객체를 useState로 관리
  const [inputs, setInputs] = useState({
    username: '',
    email: ''
  });
  
  // 구조 분해
  const { username, email } = inputs;
  
  // 객체를 수정할 때는 항상 기존의 것을 먼저 복사. 
  const onChange = e => {
    const { name, value } = e.target;
    setInputs({
      ...inputs,
      [name]: value
    });
  };
  
  // 객체 배열을 useState로 관리
  const [users, setUsers] = useState([
    {
      id: 1,
      username: 'velopert',
      email: 'public.velopert@gmail.com'
    },
    {
      id: 2,
      username: 'tester',
      email: 'tester@example.com'
    },
    {
      id: 3,
      username: 'liz',
      email: 'liz@example.com'
    }
  ]);

  // useRef로 변수 관리
  const nextId = useRef(4);
  
  const onCreate = () => {
    const user = {
      id: nextId.current,
      username,
      email
    };
    // 기존배열을 복사해오고 user추가.
    // setUsers([...uers,user]);와 같다.
    setUsers(users.concat(user));

    setInputs({
      username: '',
      email: ''
    });
    nextId.current += 1;
  };
  
  return (
    <>
      <CreateUser
        username={username}
        email={email}
        onChange={onChange}
        onCreate={onCreate}
      />
      <UserList users={users} />
    </>
  );
}

export default App;

이번 컴포넌트에서는 상태관리를 CreateUser에서 하지 않고 부모 컴포넌트인 App에서 합니다. 

input의 값 및 이벤트로 등록할 함수들을 props로 넘겨받아 사용합니다. 

 

users도 useState를 사용하여 컴포넌트의 상태로서 관리합니다. 

 

배열에 변화를 줄 때는 객체와 마찬가지로, 불변성을 지켜주어야 합니다. 

그래서 push, splice, sort 등의 함수를 사용하면 안됩니다. 만약에 사용해야 한다면, 기존의 배열을 한번 복사하고 나서 사용해야 합니다. 

 

불변성을 지키면서 배열에 새 항목을 추가하는 방법은 2가지가 있습니다. 

 

1. Spread 연산자를 사용하는 것.

2. Concat 함수를 사용하는 것.

이 있습니다. 

 

 

 

 

강의 링크

 

프론트엔드 개발 올인원 패키지 with React Online. | 패스트캠퍼스 (fastcampus.co.kr)

 

프론트엔드 개발 올인원 패키지 with React Online. | 패스트캠퍼스

프론트엔드 개발 러닝패스, 이 강의 패키지 하나로 끝낼 수 있습니다. 총 90시간 분량의 평생 소장 온라인 강의로 프론트엔드 개발자가 되세요.

www.fastcampus.co.kr

 

반응형