useMemo와 비슷한데, 이거는 callback을 캐싱하고 있는거임.
보통 우리가 props를 통해 콜백함수를 자식으로 내려준다.
그런데, 부모 컴포넌트가 리랜더링 되면 자식컴포넌트들도 리랜더링 된다.
그러면 자식 컴포넌트들은 매번 부모가 리랜더링 될 때마다 내부 동작을 다시 실행하게 된다. (아예 컴포넌트 자체가 처음부터 끝까지 실행 됨.)
다시,
useCallback은 props에 콜백함수를 자식으로 전달해도 쓸데없이 자식컴포넌트 내에서 재생성 하지 않고, 메모리에 캐싱해 뒀다가 그걸 참조해서 사용한다.
일단은 이걸 내가 이해하기 좀 어려웠던게 뭐냐면,
나는 사실 리액트 배우면서 생명주기도 create, update 순간만 알고 있었다. 그래도 리액트를 사용하는데는 아무 제약이 없으니까. 충분했다.
근데 최적화 단계에 들어서고 나니,
사실 최적화 란 것이 기존의 것에서 트레이드 오프에 의하여 그 중 필요없는 행위를 지우는 것이다.
그럴려면 기존 동작을 모두 알아야 한다. 기존 동작 자체가 뭔지 알아야 왜 최적화가 되는지 안다.
사실 사용 타이밍 뿐이면,
그냥 부모컴포넌트의 콜백을 상속받은 자식들이 많으면 이 때 useCallback을 쓰면 그 callback을 기억하니 부모로부터 다시 가져오지 않으니 그 때 쓰면 된다.
그런데 내가 좀 걱정되는게,
이런 기본동작을 모르는 상태에서 관련된 무언가를 쓰게 되면, 디버깅 하는 순간 무엇 때문에 이런 일이 일어났는지 모르게 된다.
그래서 리액트의 기본동작 자체를 알아야 하게 된다.
그래서 사실 부모의 callback을 참조하니까? 이건 가지를 안거지 나무 기둥을 안 것이 아니다.
리액트란 것 자체가 최적화를 위해 본인들이 만들어 놓은 패턴이나, 시스템이 있다. 그래서 그걸 새로 이해하고 배워야 한다.
그래서 이게 리액트 개발자의 시선으로 봐야 이해가 된다.
그게 어려운 거다.
지금까지 리액트를 수박 겉핥기 식으로 알았는데, 이렇게 되면 진짜 약간 좀 깊숙하게 알아야 한다.
하긴 또 그래야 제대로 된 리액트 개발자이긴 하다.
부모의 콜백을 사용하던 자식들이, 그 중 하나가 그 콜백에서 사용하던 것의 값이 바뀌면, 또 그것이 부모로 올라와 부모의 콜백 자체를 바꾼다. 부모의 것을 참조하던 것 이었으니까. 그럼 그 바뀐것을, 이걸 참조했던 모든 자식들에게 바뀌었기 때문에 최신화를 해 줘야 한다.
이걸 알려면 이제 랜더링이 얼마나 어느 범위까지 전파되는지, 랜더링이 전파되는 트리거, 등등등 리액트를 이용해 개발하는 사람이 아니라 리액트 자체의 개발자 시선으로 알아야 한다.
아 너무 어렵다.
그럼 내가 알아야 할 것을 정리해보자.
우선 진짜로 useCallback 입장에서만 보자.
일단 우선적으로 재랜더링 되는 타이밍부터 알아야 한다. 이거는 state? 다
아닌가? 뭔가 참조하는 콜백인가?
또 이 값이 바뀌면 이 function타입의 리액트, 이 컴포넌트 function 전체가 다시 재 랜더링 되나?
일단은 그런 것 같다.
그냥 뭐 컴포넌트 하나의 일정부분만 바꿔도 그냥 그 function 컴포넌트 전체의 그 function 자체를 다시 한번 실행하는 것 같다.
그후 그럼 재 랜더링의 trigger.
이거는 그냥 그 컴포넌트가 가지고 있던 것의 state라던지 reducer라던지 그런 것의 값이 바뀌면 재 랜더링이 일어나는 것 같다.
그런 종류가 있는 것 같다. 반응성을 위한 것, 이런 것들의 값이 바뀐 다는 것이 트리거이다.
반응성이라고 했으니 반응성 자체가 뭔가의 바뀜, 화면의 바뀜, 즉 재 랜더링의 필요성이 명명백백하다.
즉, 무언가의 값이 바뀌었다고 무조건 재 랜더링을 하는 것이 아니라 이런 반응성의 종류에 해당하는 것의 값이 바뀌어야 재 랜더링이 일어나는 것이다. 그게 트리거다.
그럼 랜더링의 전파.
이거는 그냥 부모함수 컴포넌트를 천천히 살펴보면 답이 나온다.
부모가 자식을 호출한다.
그러니까, 부모가 자식을 읽어들이는 것이다.
부모가 자식을 호출하는 것이다.
말 그대로 함수다.
그냥, 기본적인 프로그래밍의 함수 원리에 의해 재 랜더링이 전파되는 것이다.
전파라기 보다는, 그냥 사실 한 몸이다. 뭉쳐져 있는 것이다.
그냥 부모의 일부분인 것이다.
재귀함수를 생각해봐라.
이 리액트는, return안에 자식 컴포넌트를 호출하는데, 그게 쌓이고 쌓여 결국 index.js로 가서, render() 함수 안에 인자로써 도착하게 된다.
만약 이 부모 컴포넌트를 빼면, 그냥 덩어리를 빼는 것이다.
그럼 지금도 사실 추상적이긴 하지만, 어느정도 이해가 되었다.
useCallback을 사용하기 전은,
callback이 바뀌었으니, 그냥 기본동작 자체가 값이 바뀌어서 재 실행 해주는 거다.
근데 그게 부모꺼니깐, 영향받은, 영향을 받았다기 보다는 그 callback을 가지고 있는 그 부모 자체를 재 랜더링 해 주는 것이다. 그러므로 자식들도 부모 컴포넌트의 일부분이므로 재 랜더링 되는 것이다.
이거 외에도 트리거라 부를 수 있는 것이, 기존에 참조하고 있던 callback이 값이 바뀌었으므로 최신화를 위해 자식들을 모두 재실행 해주는 것이다.
아 아직도 헷갈린다.
callback을 가지고 있기 때문에 재 랜더링? 아니 그건 그럴 필요가 없다.
근데 또 이거 provider처럼 전역변수같은 개념도 있을텐데 그럼 그건 어떤거지?
callback의 주인이 부모이기 때문에, 그로 인해 부모가 재 랜더링 되면서 일부분인 자식도 재 랜더링 되는 것도 명확하고,
callback이 바뀌었기 때문에, 아, 그러면 provider처럼 전역으로 봐도, callback의 주인이 있기 때문에, 이것도 trigger가 된다는..
내가 보기에는 callback 자체보다는 값이 변경되는 부분이 중요한데..
callback은 아무리 이름이 useCallback이라 할 지라도 관련이 없어보인다.
여튼 trigger가 되는 이유가 한가지가 아니기에 더욱 헷갈린다. 뭐 때문에 재 랜더링이 되는거지?
일단 부모자식 관계의 재 랜더링 trigger는 명확한데..
일단 솔직히 말해 이 부분은 전역변수 그 쪽을 봐야 알 수 있을 것 같다.
이거 보면서 든 생각이,
뭐 콜백을 기억한다 그런 것 보다는, 그냥 자바스크립트의
e.stopPropagation()이라는 느낌이었다.
그냥 부모로 이벤트가 전파되는 것을 막는 느낌이었다.
딱 값이 바뀐 컴포넌트만..
아 헷갈려..
딱 값이 바뀐 컴포넌트만 부모의 callback을 다시 가져오지 않고 메모리에 있는 callback을 실행.
왜 거기 인자로 들어가는 것은 이제 컴포넌트마다 다르니까, 말 그대로 종속성 배열인데, 그 종속되어진 배열에 있는 값이 변경되면 그게 트리거..
오랫동안 말한 트리거는 재랜더링의 트리거고, 지금말한 트리거는 useCallback의 트리거
'React' 카테고리의 다른 글
라우터 (0) | 2023.11.23 |
---|---|
컴포넌트 한 파일에서 export 여러개 (0) | 2023.11.23 |
React.memo 고차 컴포넌트 (0) | 2023.11.21 |
useMemo (0) | 2023.11.21 |
useReducer (0) | 2023.11.21 |