
리엑트는 렌더링시 최적화를 위해 배치업데이트를 진행한다. 그동안 이 부분때문에 하나의 핸들러에서 리렌더링이 한번만 일어나는게 당연하다고 여겼다.
근데 ai api응답시간이 너무 길어서 로딩 UI 처리가 필요했다.
API요청 응답이 오기까지 UI가 변경되야 했고 이걸 해결하기 위해서는 API를 호출하고나서 리렌더링 한번, API응답을 받고나서 또 리렌더링 한번
이렇게 총 두번의 리렌더링이 필요했다.
보통 API요청은 하나의 핸들러에서 처리되고 그동안 구현한 방식에 따르면 한번의 핸들러 요청에는 한번에 리렌더링이 일어나는걸 당연하게 여겼다.
하지만 이번에는 두번의 변경이 필요해서 이것저것 해보다가 그냥 흐름대로 두번 상태 업데이트 함수를 작성해 봤더니 구현이 됐다!
그동안 잘못 알고있나 싶어서 알아본 결과 내가 알고있던 것도 맞고, 여러번 렌더링이 가능한 것도 맞았다. 그 이유를 작성해본다.
리엑트에서 배치업데이트는 상태를 한번에 모아서 변경시키는 것이다. 만약 내가 숫자를 1더하고 색을 바꾸는 버튼을 눌렀을 경우
상태가 그때마다 바로 바뀌는 것이 아니라 해당 버튼의 핸들러가 종료되면 한번에 업데이트 된다.
리엑트는 성능 최적화와 렌더링 효율성 때문에 배치업데이트 전략을 선택하였다고 한다.
등의 이유가 있다.
실제로 개발을 하면서 핸들어 안에서 상태가 한꺼번에 변경이 안된다는게 익숙해 진 후부턴 상태를 변경하거나 할때 쫌더 편하게 생각하고 구현 할 수 있었던것 같다.
개념적으로 실행컨텍스트가 정리되는 시점에 배치업데이트가 일어난다.
개발자가 인지할 수 있는 배치업데이트 시점은 간다하게 하나의 핸들러가 호출되고 종료되었을때 배치업데이트가 일어나고 상태가 업데이트 된다는 것이다.
나도 사실 그렇게 알고 하나의 핸들러가 종료 될때만 리렌더링이 일어나는줄 알았다.
공식문서 배치업데이트 설명에도 이벤트 핸들러의 코드가 실행되면 발생한다고 작성되어있다.
때문에 한번에 핸들러에서 리렌더링이 여러번 일어나야하는 위에서 설명한 예시에서 조금 헤맸던 것 같다.
일단 설명에 필요한 코드만 표현하자면 이런 흐름이다.
isFetching 상태는 버튼의 로딩 UI 출력 및 비활성화 여부를 조건부로 렌더링할 때 사용된다.
원래 알고있던 지식으론 이런식으로 코드를 작성했을때 핸들러가 실행되면 종료되는 시점에 isFetching이 항상 false가 된다.
그럼 여기서는 뭐가 다른 걸까?
방금 구현한 코드에는 코드 실행 중간에 await가 껴 있다.
await 전에 리렌더링이 한번 일어나고 await가 정리되어 핸들러가 끝날때 리렌더링이 한번 더 일게나게 되는 것이다.
결론부터 말하자면 비동기 흐름 중단점에서 배치업데이트가 한번 정리가 된다는 것이다.
이는 자바스크립트 동작과 리엑트 배치업데이트 시점에 대한 동작이 조화되어 일어나는 현상이다.
일단 자바스크립트에 await ,then인 비동기 중단점을 만나면 그 이후 코드들은 새로운 컨텍스트에서 실행되게 된다.
배치업데이트 시점은 실행컨텍스트 종단에 실행되기 때문에 비동기 함수 전후로 리렌더링 동작이 일어나게 되는 것이다.
요약하자면 await는 실행컨텍스트를 분리하게 되고 실행컨텍스트가 끝날때 상태가 업데이트되는 리엑트의 특성 때문에 하나의 핸들러에서 리렌더링이 여러번 발생할 수 있게 된 것이다.
나름 promise에 대해 이해하고 있다고 생각했는데 실행컨텍스트 관점에 대해서는 한번 정리를 하고 넘어가야 할 것 같다.