제목에 있는 오류에 대한 해결법을 작성하고자 한다.
변경할 수 없는 배열에 대한 변경을 시도했을 경우 발생하는 에러이다.
필자는 TS + Redux Toolkit으로 받아온 데이터를 수정하고자 했고,
useSelector를 활용하여 스토어에서 꺼내온 데이터를 직접 수정하고자 했을 때
이 에러가 발생했다.
필자는 api 통신 결과로 받아온 데이터를 리덕스 스토어에 넣은 뒤,
useSelector
로 스토어에서 값을 꺼내왔고,
그 데이터 중, 배열 타입의 데이터를 reverse()
해서 보여주고 싶었다.
데이터가 잘 처리되었는지 console.log()
로 확인하고자 아래 코드로 진행했다.
// 스토어에서 데이터 가져오기
const lectureData = useAppSelector((state) => state.lecture.lectureData);
// api 통신으로 받아온 데이터를 스토어에 저장하고
// 그 중, 원하는 특정 데이터(배열)을 가지고 setState 해줌.
useEffect(() => {
dispatch(loadAllLecture(null))
.then((res) => {
if (res.payload?.lectureList) {
setLectureList(res.payload.lectureList);
}
})
.catch((err) => console.log(err));
}, []);
// setState의 비동기 처리로 인한 에러를 막기 위해
// useEffect를 사용하여 데이터를 처리해줬다.
useEffect(() => {
let arr = lectureData.lectureList.reverse();
console.log(arr);
}, [lectureList]);
가장 아래 부분에 있는 reverse()
가 문제의 코드이다.
저 부분을 작성하기 전까지는 아무런 문제가 없다가, 저 코드가 추가된 직후에
이런 에러가 발생했다.
주목할 점은 read only
이다.
읽기 전용 데이터를 필자가 바꾸려고 했기 때문에 에러가 발생한 것이다.
해결 방법은 깊은 복사
이다.
쉽게 말해, 변경할 수 없던 데이터를 복사해서 다른 변수에 넣고, 그 값을 수정하는 것이다.
// 스토어에서 데이터 가져오기
const lectureData = useAppSelector((state) => state.lecture.lectureData);
// api 통신으로 받아온 데이터를 스토어에 저장하고
// 그 중, 원하는 특정 데이터(배열)을 가지고 setState 해줌.
useEffect(() => {
dispatch(loadAllLecture(null))
.then((res) => {
if (res.payload?.lectureList) {
setLectureList(res.payload.lectureList);
}
})
.catch((err) => console.log(err));
}, []);
// setState의 비동기 처리로 인한 에러를 막기 위해
// useEffect를 사용하여 데이터를 처리해줬다.
useEffect(() => {
// 위에서 실행된 useEffect에서 lectureList라는 state를 set했었다.
// 그 state를 그대로 복사해줬다.(깊은 복사)
let arr = [...lectureList];
// 이제 데이터를 수정해도 전혀 에러가 없다!
arr.reverse();
setReversedLectureList(arr);
}, [lectureList]);
아까 봤던 코드와 지금 코드의 차이가 뭘까?
스프레드 연산자(Spread Operator) ...
을 사용했다는 것이다.
사실 스프레드 연산자가 깊은 복사인지 얕은 복사인지에 대한 말이 사람마다 꽤 다른 것 같은데..
적어도 필자가 알아본 자료들에 의하면 깊은 복사가 맞다는 말이 더 많다.
medium에서 많은 추천을 받은 분의 말을 인용하자면
The spread operator makes deep copies of data if the data is not nested.
- Kevin Lai -
직역하자면 "중첩된 데이터가 아니라면 스프레드 연산자는 깊은 복사가 된다."이다.
이 것에 관련해서는 참고 자료에 링크를 남겨두도록 하겠다.
깊은 복사와 얕은 복사에 대해서도 정확하게 정리해야겠다.