state가 배열이면, 배열 중 한 요소의 상태만 업데이트 하고 싶을 경우, 배열 안을 처음부터 끝까지 돌다가 동일한 id를 가진 상태를 업데이트 해야 한다.
그러나 이 방법은 배열의 길이가 길어질수록, map으로 배열 전체를 도는 속도가 늘어나게 된다. 또한 자주 발생하는 이벤트에 대한 상태를 이런식으로 업데이트 하게 되는 경우 성능에 좋지 않다.
따라서, 배열로 이루어진 state를 고유한 key로 접근 가능한 오브젝트 형태로 바꿔주는 것이 좋다. 어떻게 변환하면 좋을지 아래 예제를 통해 살펴 보도록 하자.
📍 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로 바꾸는 방법에 대해 알아보자.
📍 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은 표현식(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
이름이 objectName인 Object의 키들을 문자열로 바꿔서 배열로 반환해준다.
const object1 = {
a: 'somestring',
b: 42,
c: false
};
console.log(Object.keys(object1));
// expected output: Array ["a", "b", "c"]