React/HabitTracker

State 오브젝트를 수정하면?

느리지만 꾸준하게 2021. 8. 1. 18:06

리액트 동작원리에 대해서 다시보면

리액트는 변경사항이 한가지의 방향으로만 흘러간다.

데이터가 변경이 되면 => UI가 업데이트 된다.

즉, 데이터(State)가 변경이 되면 => 리액트가 render() 함수를 호출해서 UI가 업데이트 되는 것

 

리액트에서 제공하는 setState 함수를 호출하는 코드를 보면

setState 예제코드

위 코드를 보면 setState 함수를 이용하여 새로운 상태 오브젝트( 업데이트 하려고 하는 상태 데이터)를 인자로 받아 전달해 주는 것을 볼 수 있다. 리액트가 업데이트 되어야 한다고 알아 차리게 하기 위해 setState 함수를 호출해줘야 한다.

그래야 리액트가 상태가 업데이트 됐다는걸 알고 UI를 업데이트 하기 위해 render 함수를 호출하기 위해 준비하기 때문이다.

 

리액트가 내부적으로 어떻게 하는지 더 자세히 살펴보면

setState 함수가 호출되면 리액트는 현재 컴포넌트가 가진 상태와 (this.state), 업데이트 해야 하는 새로운 상태(setState 함수의 인자로 전달된 새로운 오브젝트) 두 개를 비교해 업데이트가 필요한 경우 해당 컴포넌트의 render 함수를 호출한다.

컴포넌트를 업데이트 할 때 현재 컴포넌트의 상태와 새로운 상태를 비교하는 방법은

=>

PureComponent인 경우에는 두가지를 얇게 비교해서 (제일 위에 reference만 비교, shallow comparisons를 기억해보자)달라진게 있으면 컴포넌트를 업데이트 한다.

 

일반 Component 경에는 라이프사이클 메소드중 하나인 shouldComponentUpdate를 구현하지 않으면 setState가 호출될 때마다 render 함수가 호출된다.

 

setState는 비동기 API인데

webAPIs 중 하나인 setTimeout, setInterval과 같이 setState도 비동기 함수인데, setState를 호출한다고 해서 무조건 바로 render함수가 호출되는 것은 아니라는 것이다.

리액트에 업데이트 요청을 하기만 하고 뒤에 이어지는 코드가 실행되어진다.

즉, 비동기로 동작해서 리액트가 동시다발적으로 요청된 여러개의 setState를 효율적으로 처리 할 수 있다.

그리고 state를 업데이트 할 때 이전 state값에서 무언가가 계산이 되어진 경우면 컴포넌트 내의 state 값에 의존해 계싼한 값을 setState(updated)로 설정하기 보다, setState(prevState => newState) 이렇게 이전 state 값을 받아서 업데이트 되는 state 만드는 arrow 함수를 전달할 수 있는 함수를 호출 하는게 효율적이다.

 

리액트에서 제공하는 setState에는 두가지가 있는데 

setState(newState) => 새로운 state 오브젝트를 인자로 바로 받는 함수

setState(prevState => {return newState;}) // 이전 state를 받아 계산해서 새로운 state를 리턴하는 함수를 인자로 받는 함수

그러므로 아래와 같이 코드를 작성하면 효율적이다.

setState 예시코드

만약 리액트에서 State를 직접적으로 수정을 하면

당연히 좋지않다. 오브젝트를 직접적으로 변경하면 예상치 못한 오류가 발생하기 때문에 이미 만들어진 오브젝트는 불변성을 유지하는 것이 좋다.(Immutability)

 

State를 직접적으로 수정하는게 좋지 않은 이유를 살펴보면

- setState는 비동기적으로 동작하기 때문

리액트의 setState 함수 호출은 비동기적으로 처리되는데 State를 직접 바꾸면서 상태를 업데이트 하면 이전에 업데이트 한 내용이 다음업데이트 내용으로 바뀔 수 있고, 비동기 특성으로 예상치 못한 곳에서 버그가 발생 할 수 있기 때문이다.

 

- PureComponent에서 정상적으로 동작하지 않는데

PureComponent는 현재 컴포넌트가 갖고 있는 상태와 (this.state) , 업데이트 해야하는 새로운 상태(setState 함수의 인자로 전달된 새로운 오브젝트)의 레퍼런스를 비교해서 업데이트가 필요하면 컴포넌트의 render함수를 호출해준다.

만약에 this.state 오브젝트를 직접적으로 수정해서 setState함수에 동일한 오브젝트를 전달하면, 비교하는 대상의 레퍼런스가 같아서 리액트가 업데이트 할 필요가 없다고 판단해서 render 함수를 호출하지 않는다.

 

결론적으로 리액트 상태 State를 직접적으로 바꾸는 것은 예상치 못한 문제가 발생하기 때문에 불변성을 꼭 유지해야한다.

 

 

 

<출처 : DreamCoding 리액트 개념 정리+유튜브 클론코딩: ellie>

참고: https://academy.dream-coding.com/courses/react-basic

 

리액트 강의 (유튜브 클론 코딩 + 실시간 전송 명함 카드 만들기 웹앱 만들기)

리액트 전반적인 개념 설명과 (클래스 컴포넌트와 함수 컴포넌트 그리고 리액트 훅까지) 실전 유튜브 클론 코딩 프로젝트. Firebas의 실시간 데이터베이스를 이용해 멋진 명함 카드 만들기 웹 어

academy.dream-coding.com

https://reactjs.org/docs/state-and-lifecycle.html

 

State and Lifecycle – React

A JavaScript library for building user interfaces

reactjs.org

 

'React > HabitTracker' 카테고리의 다른 글

Habit-tracker Netlify에 배포 하기  (0) 2021.08.04
Habit_tracker Github에 배포  (0) 2021.08.04
리액트 컴포넌트 종류 및 Hook에 대한 정리  (0) 2021.08.01
React Hook (중요)  (0) 2021.08.01
function 컴포넌트, memo 정리  (0) 2021.08.01