23/11/2

Laejun Kim·2023년 11월 2일
1

TIL

목록 보기
27/89

React ToDoList

Problem

각 인스턴스의 id가 겹치는 문제 발생

상황 파악

  • 기존에는 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++;
}
  • unique id 생성 방법을 검색해보는 과정에서 다음 youtube 영상도 발견했는데 커스텀 훅을 만들어서 id를 생성하는 과정을 설명하고 있다. 아직 커스텀 훅을 사용하는 방법에 대해서는 배우지 않은 상태이므로 기록만 해두고 넘어가기로 한다.
    https://www.youtube.com/watch?v=IRwsABVb9RI

React

불변성(immutability)

불변성이란?

한번 생성된 원본의 데이터는 변경시키지 않고, 데이터 변경 필요시 새로운 원본을 만드는 디자인 패턴

불변성이 없다? => 원본 데이터가 변할수 있다는 의미. 대표적으로 배열의 push 메서드
불변성이 있다? => 원본 데이터는 변할수 없다는 의미. 대표적으로 배열의 map 메서드

이게 React에서 왜 중요한가?

이유1 - 리렌더링

리렌더링이 안되는 경우가 있을수 있다. 리액트는 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 이므로 리렌더링이 발생하지 않음

이유2 - 부작용

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)

immer.js 에서 produce 메서드를 쓰는 방법도 있다.
https://immerjs.github.io/immer/produce/
위 링크에 설치방법과 간단한 예시가 있으니 적극 활용하도록 하자.

0개의 댓글