
Object.assign() 메서드나 스프레드 문법(...)을 사용하여 얕은 복사를 수행할 수 있다.let obj = { a: 1, b: { c: 2 } };
let shallowCopy = { ...obj };
shallowCopy.b.c = 3;
console.log(obj.b.c); // 3
위 예시에서 shallowCopy는 obj의 얕은 복사본이다. shallowCopy의 내부 객체 b는 obj의 b와 동일한 참조를 공유하므로, 하나를 변경하면 다른 하나도 영향을 받는다.
JSON.parse(JSON.stringify(object))를 사용하는 것이다. 하지만 이 방법은 함수, Date 객체, undefined, 순환 참조 등을 제대로 처리하지 못하는 단점이 있다.let obj = { a: 1, b: { c: 2 } };
let deepCopy = JSON.parse(JSON.stringify(obj));
deepCopy.b.c = 3;
console.log(obj.b.c); // 2
위 예시에서 deepCopy는 obj의 깊은 복사본이며, deepCopy의 변경이 obj에 영향을 끼치지 않는다.
JavaScript에서 데이터를 관리할 때, 불변성, 얕은 복사, 깊은 복사의 개념을 정확히 이해하고 적절하게 적용하는 것이 중요하다. 이는 코드의 예측 가능성, 유지보수성, 성능 최적화에 큰 영향을 미친다. 특히, React와 같은 라이브러리/프레임워크에서 불변성을 유지하는 것은 상태 관리의 핵심이며, 애플리케이션의 성능을 향상시키는 데 필수적이다.
useReducer는 React에서 복잡한 상태 관리를 위해 사용되는 훅이다. 이 훅은 상태 업데이트 로직을 컴포넌트에서 분리시켜 더욱 선언적이고 관리하기 쉬운 코드를 작성할 수 있게 해준다. 특히 복잡한 상태 구조를 가진 경우에 유용하다.
복잡한 상태란 여러 하위 값들을 포함하고, 그 값들이 서로 연관되어 있어서 상태의 일부분만 변경되더라도 다른 부분에 영향을 미칠 수 있는 상태를 말한다. 예를 들어, 사용자의 입력 양식, 여러 계층의 데이터를 포함하는 객체, 또는 배열 등이 이에 해당한다.
useReducer를 사용하여 복잡한 상태를 관리할 때, 다음과 같은 접근 방식을 취할 수 있다:
type 속성을 포함한다.import React, { useReducer } from 'react';
const initialState = {
userInfo: {
name: '',
age: 0,
hobbies: []
}
};
function reducer(state, action) {
switch (action.type) {
case 'setName':
return { ...state, userInfo: { ...state.userInfo, name: action.name }};
case 'setAge':
return { ...state, userInfo: { ...state.userInfo, age: action.age }};
case 'addHobby':
return { ...state, userInfo: { ...state.userInfo, hobbies: [...state.userInfo.hobbies, action.hobby] }};
default:
throw new Error();
}
}
function UserInfoForm() {
const [state, dispatch] = useReducer(reducer, initialState);
const handleNameChange = event => {
dispatch({ type: 'setName', name: event.target.value });
};
const handleAgeChange = event => {
dispatch({ type: 'setAge', age: event.target.value });
};
const handleAddHobby = hobby => {
dispatch({ type: 'addHobby', hobby });
};
return (
<div>
<input type="text" value={state.userInfo.name} onChange={handleNameChange} />
<input type="number" value={state.userInfo.age} onChange={handleAgeChange} />
<button onClick={() => handleAddHobby('Programming')}>Add Hobby</button>
<div>Name: {state.userInfo.name}</div>
<div>Age: {state.userInfo.age}</div>
<div>Hobbies: {state.userInfo.hobbies.join(', ')}</div>
</div>
);
}
이 예제에서는 사용자 정보를 포함하는 복잡한 상태를 useReducer로 관리한다. 각 액션은 상태의 특정 부분을 업데이트하고, 전체 상태는 불변성을 유지하면서 업데이트된다.
복잡한 객체 구조에서 불변성을 유지하려면 객체의 깊은 복사가 필요할 수 있다. 이를
위해 lodash와 같은 라이브러리의 깊은 복사 함수를 사용하거나, 직접 깊은 복사 로직을 구현할 수 있다.
Immer는 JavaScript의 불변성을 쉽게 관리할 수 있게 해주는 라이브러리이다. 이 라이브러리를 사용하면 복잡한 객체도 쉽게 불변성을 유지하면서 업데이트할 수 있다.
useReducer를 사용하면 복잡한 상태를 더욱 체계적으로 관리할 수 있다. 불변성을 유지하는 것은 리액트의 성능 최적화와 데이터의 일관성을 보장하는 데 중요하다. 이를 위해 JavaScript의 객체와 배열에 대한 이해, 순수 함수의 사용, 그리고 필요에 따라 외부 라이브러리를 활용하는 방법들을 고려할 수 있다.