기존에는 id생성을 arr.length+1
을 이용하였음. 이렇게 할 경우, id에 부여되는 숫자 자체가 배열 안에 들어있는 객체의 수로 결정이 되기 때문에 웹사이트 이용중 객체중 '삭제'를 하게 되면 중복된 id를 부여하게 될 가능성이 존재.
id는 key값으로도 재활용 하고 있기 때문에 여러 오류와 예상하지 못한 오작동이 발생함을 확인함.
위 스크린샷을 보면 상황이 더 잘 이해할 수 있음. 먼저 위에 있는 배열은 초기값으로 설정되어 있던 id:1 에 해당하는 객체를 삭제한 뒤 새로운 객체를 추가했을때 id:1 객체가 삭제되면서 array 길이가 4가 되고 이미 존재하고 있는 id:5를 중복 부여하게 되는 상황이 나타남.
또한 아래 배열에서는 id:5 에 해당하는 객체를 삭제할시 삭제를 구현하는 함수에서도 id를 기준으로 삭제 filter 메서드를 돌린 다음에 state를 재설정 하는 방식으로 동작하기 때문에 중복되는 id를 가진 다수의 객체가 함께 지워지는 것을 확인 할 수 있음. 당연히 이는 원하는 동작이 아님.
id를 부여하는 방식으로 배열의 길이는 사용할 수 없다는 것을 확인, id 부여방식을 변경하기로 함.
위와 같이 id 생성만을 담당하는 idMaker 함수를 만듬.
let idCounter = 4; //초기 toDos가 3개라서 4부터 시작.
function idMaker() {
return idCounter++;
}
한번 생성된 원본의 데이터는 변경시키지 않고, 데이터 변경 필요시 새로운 원본을 만드는 디자인 패턴
불변성이 없다? => 원본 데이터가 변할수 있다는 의미. 대표적으로 배열의 push 메서드
불변성이 있다? => 원본 데이터는 변할수 없다는 의미. 대표적으로 배열의 map 메서드
리렌더링이 안되는 경우가 있을수 있다. 리액트는 state 변경 전 후의 값을 얕은 비교하여 다른 경우에만 리렌더링 한다.
얕은 비교란? 참조값의 경우 주소끼리 비교하고, 원시값은 데이터 값 그 자체를 비교하는 것을 의미한다.
const [state, setState] = useState({a: 1, b: 2});
// 초기 state {a: 1, b: 2} 는 참조값으로 0x1234 와 같은 주소값을 가리킴.
state.a = 10; // state 값을 직접 변경해도 state는 여전히 0x1234(주소가 안바뀜)
setState(state); // 기존 state 와 변경요청온 state 모두 0x1234 이므로 리렌더링이 발생하지 않음
state의 원본 데이터를 직접 변경하는 경우(=불변성을 지키지 않는 경우), 해당 state와 연결되어있는 모든 컴포넌트에 영향을 주게 되고, 또 그렇게 영향 받은 컴포넌트와 관련된 다른 state들도 영향을 받을 수 있다. 코드가 복잡해질수록 점점 예측하기 힘들어지고 유지 보수하기 힘들어진다.
그래서 코딩할 때 불변성을 의식해야 한다. 배열이 있다면 원본 배열은 변경하지 않으려 해야하고, 객체가 있다면 원본 객체 내부의 값을 바꾸지 않으려고 해야 한다.
const [obj, setObj] = useState({
name: "James",
age: 30
})
const increaseAge = () => {
setObj({...obj, age: obj.age + 1});
// setObj({name: "James", age: 30, age: obj.age + 1});
}
위와 같은 방식으로 원본을 변경하지 않으면서 원하는 결과를 얻을 수 있다.
만약 depth가 깊다면 아래 예시처럼 스프레드 연산자를 중첩해서 사용하면 된다.
const [obj, setObj] = useState({
name: "James",
contact: {
email: "abc@gmail.com",
phone: "010-1234-5678"
}
})
const changeEmailTo = (newEmail) => {
setObj({ ...obj, contact: {...obj.contact, email: newEmail} })
}
immer.js 에서 produce 메서드를 쓰는 방법도 있다.
https://immerjs.github.io/immer/produce/
위 링크에 설치방법과 간단한 예시가 있으니 적극 활용하도록 하자.