본문 바로가기

Web + APP/React

[리액트 스터디] - Queueing a Series of State Updates

반응형
SMALL

state 변수를 설정하면 큐에 다음 렌더링이 들어간다고 했음.

 

근데, 다음 렌더링을 큐에 넣기 전에 그 값을 가지고 다른 수행도 하고 싶을 때가 있을거 같은데,,,,

 

이 시점을 어떻게 조절할 수 있을까 ?

 

React state batches 업데이트

 

 

react.dev - CodeSandbox

react.dev using react, react-dom, react-scripts

codesandbox.io

 

이 전 장에서 한 번에 3씩 증가하는게 아닌 1씩 증가하는 것으로 알 수 있었다.

 

state의 값은 그 시점의 값으로 고정되어 있기 때문이라 했는데, 한 가지 더 알아둬야 할 점이 있다.

 

React는 state 업데이트 하기 전 이벤트 핸들러의 모든 코드가 실행될 때까지 기다린다.

 

 

 

어떤 손님이 "양념 치킨 시킬게요. 아 아니다 간장으로 주세요. 아 근데 좀 비싸네 그냥 후라이드로 하나 주세요"

 

라고 한다면, 웨이터는 주방을 왔다갔다하며 "양념이요 ~ => 아 아니다 간장으로 바꿔주세요 ~ => 결국은 후라이드네요 ~" 하는게 아니고 걍 바로 "후라이드 하나요" 하는거임

 

심지어 "후라이드 하나"를 기억했다가 다른 테이블의 주문도 받을 수 있음

 

이렇게 하면 리렌더링이 많이 일어나는걸 방지할 수 있음

 

그리고 다수의 주문도 처리가 가능함. 즉, 다수의 state 변수 업데이트도 가능하다.

 

단 !!!

 

이러면, 모든 주문을 받기 전까지 요리가 시작되지 않는다는 것과 같다.

 

코드가 완료되기 전까지 UI가 업데이트 안된다는 뜻

 

batching을 사용하면, React 앱을 빠르게 실행할 수 있게 해줌 !

 


다음 렌더링 전에 동일한 state 변수를 여러 번 업데이트 하기

해당 시점의 고정된 state를 사용하지 않고, 렌더링 전에 여러 번 업데이트 하려면 !?

 

단순히 state 값을 대체하는게 아닌 "state 값으로 무언가를 하라"고 지시하는 방법으로 가능하다.

 

함수를 전달한다는 뜻

 

setNumber(number + 1) => setNumber(number => number + 1)

 

 

react.dev - CodeSandbox

react.dev using react, react-dom, react-scripts

codesandbox.io

 

이제 3씩 올라감을 확인 가능함.

 

여기서 n => n + 1 을 업데이터 함수(updater function)라고 함

 

React가 이벤트 핸들러의 모든 코드를 실행한 후 해당 함수를 큐에 넣음.

 

그리고 순차적으로 업데이터 함수를 수행하고, 최종적인 state를 제공하여 렌더링이 큐에 들어가게 되는거임

 

queued update (큐에 쌓인 함수) n returns
n => n + 1 0 0 + 1 = 1
n => n + 1 1 1 + 1 = 2
n => n + 1 2 2 + 1 = 3

 

그래서 +3을 클릭하면 3씩 올바르게 증가하게 되는거임


state를 교체한 후 업데이트하면 어떻게 되나요 ?

<button onClick={() => {
  setNumber(number + 5);
  setNumber(n => n + 1);
}}>

 

그렇다면 위의 코드는 어떻게 될까 ?

 

아까 말했듯이 최종 업데이트된 state가 제공된다고 했음

 

그래서 위의 버튼을 클릭하면 6씩 증가함

 

 

 

react.dev - CodeSandbox

react.dev using react, react-dom, react-scripts

codesandbox.io

 

queued update n returns
"replaced with 5" 0 (unused) 5
n => n + 1 5 5 + 1 = 6

 

setState(5)가 결국엔 setState(n => 5)처럼 동작하는건데 n이 사용안되는거임.

 

생략된거지

 

업데이트 후 state를 바꾸면 어떻게 될까 ?

아래의 코드는 어떻게 될까 ?

<button onClick={() => {
  setNumber(number + 5);
  setNumber(n => n + 1);
  setNumber(42);
}}>

 

 

 

react.dev - CodeSandbox

react.dev using react, react-dom, react-scripts

codesandbox.io

 

 

queued update (큐에 쌓인 함수) n returns
"replace with 5" 0 (unused) 5
n => n + 1 5 5 + 1 = 6
"replace with 42" 6 42

 

좀 헷갈림

 

// number는 렌더링 시점의 스냅샷
setNumber(n => number + 1);
// n은 연산 시점의 값
setNumber(n => n + 1);
// 걍 상수
setNumber(n => 42);

// 위의 로직은 동기적으로 실행된다.

 

로 이해했음.

 

근데 우얐든 헷갈리니, 업데이터 함수는 순수해야 사이드 이펙트를 줄일 수 있음

 

React Strict 모드는 각 업데이터 함수를 두 번 실행하여 순수 함수인지 아닌지를 찾아주기 때문에 개발에 도움이 됨

 

명명 규칙

업데이터 함수 인수의 이름은 해당 state 변수의 첫 글자로 지정하는 것이 일반적 !

 

setEnabled(e => !e);
setLastName(ln => ln.reverse());
setFriendCount(fc => fc * 2);

 

좀 더 자세한 코드를 원하면 (내 스타일)

 

setEnabled(enabled => !enabled)
setEnabled(prevEnabled => !prevEnabled)

 

이렇게도 가능

 

근데 나는 setEnabled(prevEnabeld => !prevEnabled) 이게 좋당


 

 

state 업데이트 큐 – React

The library for web and native user interfaces

ko.react.dev

 

문제가 있는 코드는 클릭 시점의 state를 가지고 연산을 하는게 문제임

 

setPending(pending + 1); // 이 때 0이고
await delay(3000);
setPending(pending - 1); // 3초 뒤에 연산에서도 0으로 해버림
setCompleted(completed + 1);

 

그래서, 연산 시점의 값을 가지고 제어하고 싶으면 업데이터 함수를 넘기면 됨

 

그러면 클릭 당시가 아닌 최신 state를 가지고 카운터를 줄이거나 늘리는게 가능

 


 

 

react.dev - CodeSandbox

react.dev using react, react-dom, react-scripts

codesandbox.io

 

setState가 어떻게 동작하는지 이해할 수 있게되는 문제인데, 좋은 문제인거 같다.

 

export function getFinalState(baseState, queue) {
  let finalState = baseState;

  queue.map(q => {
    if (typeof q === 'number') {
      finalState = q;
    } else {
      finalState = q(finalState);
    }
  })

  return finalState;
}

 

난 이렇게 품

반응형
LIST