Selected 배열을 다른 Component의 데이터와 취합해 BackEnd로 전달하기 위해 selected가 변경될 때마다 sessionStorage에 저장하는 function을 만들었다.
useEffect(() => {
const selectedEl = selected.map((item) => {
return item.name;
});
sessionStorage.setItem("selected", selectedEl);
}, [selected]);
그런데 selected에 추가될 때는 잘 실행되던 function이 삭제할 때는 미동도 없는 현상이...?
Selected item의 onClick function
<EachVariable
onClick={() => {
setArr([...arr, item]);
selected.splice(selected.indexOf(item), 1);
}}
selected.splice(selected.indexOf(item), 1);
여기에서 두 가지 문제를 발견했다.
먼저, splice method를 적용한 배열이 반환하는 값은 splice의 대상이 제외된 배열이 아니라, 대상이 되는 item이다.
console.log(selected.splice(selected.indexOf(item), 1))
즉 여기서 console.log를 확인해보면, 콘솔 창에서는 내가 클릭한 아이템을 확인할 수 있다. 이 아이템이 배열에서 splice되는 것이다.
위 코드에서는 selected 배열에 직접 접근했고, 새로운 배열로 setState해주지 않았다. React의 state를 업데이트 할 때, 기존의 데이터를 건드리지 않고 setState를 이용한다. 배열의 경우에도 마찬가지로 직접 push/pop하여 기존 배열을 변경하는 게 아니라 concat이나 spread operator를 사용한다. 여기서는 spread를 이용하기로 한다.
이 두 가지 문제를 해결한 코드는 다음과 같다.
<EachVariable
onClick={() => {
setArr([...arr, item]);
const selectedArr = [...selected];
// 기존 배열을 변경하지 않는 새로운 배열을 변수에 담는다.
selectedArr.splice(selected.indexOf(item), 1);
// 새로운 배열에서 클릭한 item을 splice하고
setSelected(selectedArr);
// selected를 새로운 배열로 setState한다.
}}
>
selected에 item 추가, 삭제 시 모두 sessionStorage에 업데이트 성공!
얼마 전 코어자바스크립트 독서모임에서 이야기했던 내용인데 실제 잘못 사용한 예시를 내 코드에서 보게 되다니 절망스럽기도 하고 반갑기도 했다 (?) 앞으로는 불변성 유지 꼭 유의하자!