React - State 변환 (배열→오브젝트) +Computed property

Noma·2021년 5월 7일
0

About

state가 배열이면, 배열 중 한 요소의 상태만 업데이트 하고 싶을 경우, 배열 안을 처음부터 끝까지 돌다가 동일한 id를 가진 상태를 업데이트 해야 한다.

그러나 이 방법은 배열의 길이가 길어질수록, map으로 배열 전체를 도는 속도가 늘어나게 된다. 또한 자주 발생하는 이벤트에 대한 상태를 이런식으로 업데이트 하게 되는 경우 성능에 좋지 않다.

따라서, 배열로 이루어진 state를 고유한 key로 접근 가능한 오브젝트 형태로 바꿔주는 것이 좋다. 어떻게 변환하면 좋을지 아래 예제를 통해 살펴 보도록 하자.

예제 코드 설명

  • 상위 컴포넌트(Infos)에서 state를 가지고 있고 이를 이용해 하위 컴포넌트(Info, View)를 렌더링 해준다.
  • 하위 컴포넌트(Info)의 input 값이 변경될 때마다 onChange의 콜백함수가 실행된다.
  • 이때 변화가 발생했던 요소의 value를 상위 컴포넌트로 전달해 state를 업데이트 해준다.
  • 업데이트된 state로 다시 하위 컴포넌트들이 리렌더링된다.

배열 state

📍 infos.jsx

import React, { useState } from 'react';
import Info from './components/info';
import View from './components/view';

const Infos = () => {
  const [infos, setInfos] = useState([
    {
      id: '1',
      name: '홍길동',
      phone: '010-1111-2222',
    },
    {
      id: '2',
      name: '이순신',
      phone: '010-7777-3333',
    }
  ]);
  const updateInfos = info => {
    setInfos(infos => {
      const updated = infos.map(item => {
        if (item.id === info.id) {
          return { ...info };
        }
        return item;
      });
      return updated;
    })
  }

  return (
    <div>
      {infos.map(info => (
        <Info
          key={info.id}
          info={info}
          updateInfos={updateInfos}
        />
      ))}
      {infos.map(info => (
        <View
          key={info.id}
          info={info}
        />
      ))}
    </div>
  );
}
export default Infos;

📍 info.jsx

import React, { useRef } from 'react';

const Info = ({ info, updateInfos }) => {
    const nameRef = useRef();
    const phoneRef = useRef();

    const { name, phone } = info;
    const onChange = event => {
        event.preventDefault();
      // 아래의 key 설정 방법이 낯설다면 하단의 문법 파트를 먼저 보자.
        updateInfos({
            ...info,
            [event.target.name]: event.target.value,
        });
    }
    return (
        <form>
            <input
                ref={nameRef}
                type="text"
                name="name"
                value={name}
                onChange={onChange}
            />
            <input
                ref={phoneRef}
                type="text"
                name="phone"
                value={phone}
                onChange={onChange}
            />
        </form>
    );
};
export default Info;

📍 view.jsx

import React from 'react';

const View = ({ info }) => <div>
    <h2>{info.name}</h2>
    <p>{info.phone}</p>
</div>

export default View;

이어서, State를 Object로 바꾸는 방법에 대해 알아보자.

오브젝트 state

📍 infos.jsx

import React, { useState } from 'react';
import Info from './components/info';
import View from './components/view';

const Infos = () => {
  const [infos, setInfos] = useState({
    // 🌈 오브젝트로 변경 
    '1': {
      id: '1',
      name: '홍길동',
      phone: '010-1111-2222',
    },
    '2': {
      id: '2',
      name: '이순신',
      phone: '010-7777-3333',
    }
  });
 
  const updateInfos = info => {
    setInfos(infos => {
      const updated = { ...infos };
      updated[info.id] = info;
      return updated;
    })
  }

  return (
    <div>
      //Object.keys()에 대해 모른다면 하단의 문법 파트를 먼저 보자.
      {Object.keys(infos).map(key =>
        <Info
          key={key}
          info={infos[key]}
          updateInfos={updateInfos}
        />
      )}
      {Object.keys(infos).map(key =>
        <View
          key={key}
          info={infos[key]}
        />
      )}
    </div>
  );
}
export default Infos;

이렇게 하면 아래와 같이 바로 바로 state가 업데이트 되는 것을 확인해 볼 수 있다. (결과는 배열 state일 때랑 동일함)


위 예제에서 쓰인 JS문법을 간단히 정리해 보겠습니다.

Computed property name

computed property name은 표현식(expression)을 이용해 객체의 key 값을 정의하는 문법으로, 대괄호([])로 속성을 읽고 설정하는 데 사용 가능하다.

속성 접근자 구문의 괄호 표기법을 연상된다.

📍__ 예시

let i = 0
let a = {
  ['foo' + ++i]: i,
  ['foo' + ++i]: i,
  ['foo' + ++i]: i
}

console.log(a.foo1) // 1
console.log(a.foo2) // 2
console.log(a.foo3) // 3

Object.keys(objectName)

이름이 objectName인 Object의 키들을 문자열로 바꿔서 배열로 반환해준다.

const object1 = {
  a: 'somestring',
  b: 42,
  c: false
};

console.log(Object.keys(object1));
// expected output: Array ["a", "b", "c"]

📝 Reference

profile
오히려 좋아

0개의 댓글