[리액트] 리액트 상태변화는 어떻게 감지될까
카테고리: react
태그: deep dive
🚀Introduction
리액트의 상태변화는 어떻게 감지될까? 사실 답은 매우매우 간단하다. 삼중등호(strict equality)로 파악된다.
const isChanged = 이전상태 === 지금상태;
사실 거짓말이다. 쉽게 이해해보자면 위처럼 측정한다. 실제 작동은 아주 조금 차이점이 있는데 어떤 차이점이 있는지 알아보도록 하겠다.
⭐️리액트에서는 어떻게 동작함?
실제 동작은 Object.is(출처: mdn) 를 이용해서 동작한다.
const isChanged = Object.is(이전상태, 지금상태);
위 값이 바뀌게 되면 값이 바뀌었다고 인지하게 된다. 사실 이게 끝이다. 삼중등호와 Object.is
메소드는 거의 차이가 없다. 사실 별내용이 없어서 필자는 글을 쓸까말까 고민했었지만, 공부하면서 알게되었던, 조금 시간을 들여서 공부했던 내용들을 공유해보는게 좋겠다 싶어서, 세부적인 차이점과 react
에서의 작동과 react-query(tanstack)
에서는 어떻게 동작하는지에 대해, 그리고 현업 혹은 코딩테스트 등에서 어떻게 적용될 수 있을지에 대해 고민한 부분을 적어볼까 한다.
⭐️Object.is와 삼중등호(는는는)와의 차이점
Object.is(a, b)
와 a === b
의 차이점은 뭘까? 두가지 차이점이 있다.
Object.is
는 NaN과 NaN을 비교할수 있다.Object.is
는 +0 과 -0을 비교할 수 있다.
위와같이 두가지 차이점이 있다. 사실 +0과 -0을 비교할일이 얼마나 많이 있으려는지 모르겠다. 하지만 렌더링시 NaN에서 NaN으로 바뀌었다면 굳이 렌더링을 다시할 필요가 없으니 유용하다고 생각한다. 결국 조금 더 strict하게 검사해줄수 있다 라고 이해하면 좋을 것 같다.
⭐️언제쓰일까?
크게 두가지로 볼 수 있을 것 같다.
- useState, 즉 컴포넌트 내의 상태값이 바뀌었는지 검사할때 쓰인다.
- useEffect내의 dependency array에서 값이 바뀌었는지 검사할때 쓰인다.
(물론 dependency array를 사용하는 다른 함수들에서도 많이 쓰인다.)
실제 dependency array를 리액트 내부적으로 어떻게 검사하는지는 여기(github) 를 들어가보면 알 수 있다.
위 링크를 들어가면 나오는 116번째 라인은, 위와같이 이전상태와 이후상태를 비교한다.
if (is(nextDeps[i], prevDeps[i])) {
continue;
}
아마 들어가봐도 다른 코드는 너~무 복잡하기때문에, 그리고 리액트라이브러리 개발자도 아니기때문에 맥락을 모를수밖에 없고, 당연히 코드들이 거부감이 들고 읽기 어려운 것 같다. ( 다들 아닌가요? 구조가 너무 복잡하니 저는 거부감이 드네요…쩝) 무튼, 비교해야 할 dependency array내부를 쫘아악 순회하면서 is
라는 함수로 합니다. 하지만 Object.is
를 직접 사용하지 않고 아래와 같이 별도로 구현해서 사용한다는것을 볼 수 있습니다.
⭐️리액트에서의 Object.is 진짜 구현
아래와 같이 구현되어있는데 너무 복잡하다…!!!
function is(x: any, y: any) {
return (x === y && (x !== 0 || 1 / x === 1 / y)) || (x !== x && y !== y);
}
const objectIs: (x: any, y: any) => boolean =
// $FlowFixMe[method-unbinding]
typeof Object.is === "function" ? Object.is : is;
export default objectIs;
왜 이렇게 구현되어있을까?
polyfill
로 구현된거라고 이해하면 좋을 것 같다. 주목할만한 부분은 아래와 같다.
typeof Object.is === "function";
이게 참이면 실행환경에 Object.is가 존재한다는 뜻이기 때문에 Object.is
를 그대로 사용한다. 만약 그렇지 않다면 위에서 복잡하게 작성된(polyfill 함수) is
를 사용하는 것이다. 실행이 안되는곳도 있어? 라고 궁금할때, 써도 될지 물어보고 싶을때는 can i use에 물어보면 된다
나온지 한참지난 ES6 문법이지만, 약 3.6%의 브라우저는 아직 사용이 어려운 것 같다.
⭐️결론 및 생각
- 리액트에서의 상태변화 및 dependency array의 변화는 삼중등호(strict equality)를 사용해서 검사한다.
- 하지만 사실 삼중등호보다 아주살짝 더 strict한 Object.is로 검사한다.
- 상태의 변경, dependency array의 변화는 Object.is로 검사한다.
- 하지만 사실 리액트 내부적으로는 ES6를 사용할수 없는 환경이라면 자체 검사함수를 사용한다.
라이브러리를 만든다는것은 전체적인 구조에 대한 설계도 어렵겠지만, 최신문법이 지원되지 않는 환경을 위해 저런 polyfill까지 고려하여 만들어야하며 정말 어렵겠다라는 생각이 들었다. 하지만 한편으로는 babel등을 사용하면 어차피 Object.is가 자연스럽게 잘 변환되지 않을까? 너무 유난인거 아닌가? 라는 생각이 들었다. 하지만 리액트급의 well-known 라이브러리라면, babel 혹은 외부 환경에 의존하지 않고 독립적으로 잘 작동하기 위한 노력이 필요하고, 결국 그렇게 하는게 맞을 것 같다는 생각이 들었다.
신입개발자일때는, facebook에서 리액트라이브러리를 개발하는건 정말 멋있는 일이라고 생각했다. 혹은 다른 유명 테크기업에서 많은 개발자들이 쓰는 툴을 만드는건 멋있는 일이라고 생각했다.
저는 리액트개발자입니다ㅎㅎ 아, 물론 여러분과는 다르게 단순 리액트로의 개발이 아닌, 리액트 라이브러리를 만들고 있습니다 후훗
하지만 저런 디테일한 부분을 하나하나 챙기는게 그렇게 우아한일은 아닐수도 있겠구나 라는 생각이 들었다. 물론 멋있는 일이고, 한번쯤 해보고 싶은 일이며, 개발자 커리어로써도 매우 가치가 높은 일이라고 생각한다. 하지만 정말 예외적인 케이스를 고려하고, 모든 케이스에 대해 생각하고 하나하나 코드로 막아두는 작업등을 하는 일들은 서비스에서 예외처리 하는것과 본질이 같지 않나? 라는 생각이 들었다.
물론 facebook에서 돈주고 시켜주신다면 감사합니다 하고 트라이 해보겠지만, 큰 관점에서는 업의 본질이 크게 다르지 않은 것 같다고 생각된다. 지금 하는일에 잘 몰입하는게 중요할 것 같다.
(이 글의 조회수와 댓글이 발생하면) 다음글은 react-query(tanstack)에서의 쿼리키 비교는 어떻게 이루어지는지와 현업&코딩테스트에서의 활용방안에 대해 작성해보도록 하겠다.
댓글 남기기