두피만
FE 던지기
두피만
전체 방문자
오늘
어제
  • 분류 전체보기
    • 기술 경험
    • 기술에 대한 생각들
    • 회고록
    • 프로그라피
    • 구 게시글
      • 백엔드 찍먹
      • 삽질
      • React
      • 라이브러리 소개
      • Breaking 프로젝트

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 전역상태
  • 노드버드
  • 프로그라피
  • react
  • 프로그라피 React
  • 삽질
  • 서비스 발전 과정
  • 프로그라피 8기
  • 상태관리
  • 아이디어 도출
  • 리엑트 노드버드
  • JS로 React 구현하기
  • SVG
  • 셀프다이닝
  • react-query
  • query string
  • 프론트엔드
  • Redux
  • Modal
  • typescript

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
두피만

FE 던지기

React 상태관리와 불변성
구 게시글/React

React 상태관리와 불변성

2022. 5. 29. 12:24

react의 상태를 관리하다보면 불변성을 지켜서 사용하라고들 한다. 굳이 데이터를 추가할때도

array.push(5);

위의 push방법이 아닌

newArray=[...array, newData];

이런식으로 spread 방법을 사용해서 데이터를 넣고 한다 이는 불변성을 지키려고 일부러 이런 방법으로 사용한다.

 

 

불변성

불변성부터 이야기해보자면 값이나 상태를 변할수 없는것이다 즉 새로운값이 생기면 상태를 변경해주는 것이아니라 새로 할당하는 것을 말한다.

대표적으로 원시타입이 이렇게 동작한다

let a = 3;
//원시타입

3이라는 변수를 할당했다

let a = 5;

5로 변경을 하면 메모리에서는 a라는 변수에 5를 다시 할당하게된다 이는 불변성을 지키고있는 것이다.

 

 

원시타입이 있으면 참조타입도 있다

js에서 변수를 할당할때 메모리 시점 call stack은 지역변수 원시타입 등 여기서 저장 Heap은 참조 타입 변수 저장

let arr = [1,2,3,4,5,6]
//참조타입

배열은 heap에 배열을 할당하고 call stack에는 이 저장된 주소값을 저장한다.

여기서는 [1,2,3,4,5,6]이 heap에 할당이 되고 arr는 이 heap의 주소값을 가지고 있는것이다

arr[2]를 10으로 변경한다고 하자

let arr = [1,2,10,4,5,6]

이렇게 되면 메모리에서는 arr를 다시 할당하는 것이 아닌 안에있는 값만 바뀌는 것이다 이는 불변성이 지켜지지 않았다고 할수있다.

 

 

React

React로 다시 돌아와 보자 React의 state가 변경할때 비교하는것은 데이터 하나 하나가 아니라 새로 할당되었는지를 확인해서 새로 할당 되었으면 state가 변경되었다고 감지하고 리랜더링을 수행한다.

이는 Array나 Object의 값이 불변성을 지키지 않고 바꾼다면 React에서는 값이 변경되었다고 파악하지 못한다.

const [state, setState] = useState({ id: 13, age: 30 })
setState({...person, age: 20})

다음과 같이 spread를 이용해서 불변성을 지키면서 변경해야 한다

( 새로 배열을 반환해주는 filter,mapm, concat 등을 사용해주어야 한다)

 

 

redux를 사용했으면 debug 툴로 redux dev tools를 많이 사용해 봤을것이다.

우리가 보는 redux dev tools에서도 불변성을 지켜야 수정 전의 state와 후의 state가 서로 달라지면서 재 할당 되기 때문에 이를 감지하여 action시에 state 변화를 dev tools로 볼수 있는 것이다.

 

 

 

코드 상으로는 reducer를 사용했을때 직접 와닿을수 있었다 데이터를 가공할때 이 불변성을 지키려다보면 코드들이 매우 난해해 지고 하나만 잘못해도 전부 무너저 버리는 상황이 발생하였다

다음은 댓글을 작성하는 reducer를 작성한 것이다.

//before
case ADD_COMMIT_SUCCESS:{
	const postIndex = state.mainPost.finIndex((y)=>y.id===action.data.postId);
	// 불변성을 지키면서 mainPost에서 알맞는 index를 가져와야함
	const post ={...state.mainPosts[postIndex]};
	// 불변성을 지키면서 찾은 index를 통해서 mainPosts의 개시글을 불러옴
	post.Comments = [...post.Comments,action.data)
	// 불변성을 지키면서 post에 Comment를 추가한다
	const mainPosts = [...state.mainPosts];
	// mainPosts를 불러온다
	mainPosts[postIndex] = post;
	// mainPosts에 수정된 post를 넣어준다
	return{
		...state,
		mainPosts,
	}
}

action.data에 API 호출후 응답 받은 데이터가 여기 들어있다 위의 상황에는 이렇게 들어가 있다고 생각하고 읽어주시길 바란다.

action.data{
	postId: Number
	content: String
	userId: Number
}

이런코드는 구조가 복잡해 보이고 직관적이지 않는다

 

그러면 이런 방법을 해결할 방법이 없을까?

 

 

Immer

 

사실 이 불변성을 지키지 않고 코드를 짜는것이 지키면서 짜는것보다 직관적이게 짤수 있다 이를 해결해 주는 것이 바로 Immer 라이브러리이다. 우리가 불변성을 지키지 않고 사용하면 Immer가 직접 불변성 관리를 대신 해주는 것이다.

//after
case ADD_COMMENT_SUCCESS: {
  const post = draft.mainPosts.find((v) => v.id === action.data.postId);
	// main포스트에서 알맞는 개시글 찾기
  post.Comments.unshift(action.data);
	// 찾은 post에 댓글을 추가한다
  break;
}

불변성을 지키지 않고 사용하면 단 두줄로 끝난다.

우리가 직관적으로 생각해봐도 댓글을 추가하려면 1. 댓글달 개시글을 찾고 2. 댓글을 추가한다가 알맞는다.

 

Immer을 사용한다고 무조건 코드가 짧아지거 하지는 않는다 오히려 짧은 코드들은 더 길어질수도 있다 위의 상황처럼 데이터 가공을하거나 할때 적절하게 사용하면 코드의 직관성과 간결함을 줄 수 있다.

'구 게시글 > React' 카테고리의 다른 글

JS 프로젝트 TS로 마이그레이션하기  (0) 2022.11.25
CSR SSR SSG(NEXT JS) SPA MPA 정리  (0) 2022.06.19
SVG 태그  (0) 2022.05.22
props로 modal관리는 이제 그만  (0) 2022.05.17
    '구 게시글/React' 카테고리의 다른 글
    • JS 프로젝트 TS로 마이그레이션하기
    • CSR SSR SSG(NEXT JS) SPA MPA 정리
    • SVG 태그
    • props로 modal관리는 이제 그만
    두피만
    두피만

    티스토리툴바