원문: https://typeofnan.dev/what-the-useevent-react-hook-is-and-isnt/
지난주 리액트 코어팀은 새로운 리액트 훅인 useEvent
에 대해 RFC([역주] RFC: Request For Comment, 개발에 있어 필요한 기술, 연구 결과, 절차 등을 기술해놓은 메모)를 발표했습니다. 이 훅이 무엇인지, 또 무엇이 아닌지, 그리고 훅에 대한 제 생각을 전달드리고자 합니다.
이 내용은 RFC이기 때문에 출시된 것이 아닙니다. 따라서 아직 사용할 수 없으며 세부 동작이 변경될 수 있다는 점 유의 부탁드립니다.
useEvent
가 해결하고자 하는 문제가 있습니다. useEvent
가 무엇인지 알아보기 전에, 해결하고자 했던 문제가 무엇인지 확인해 봅시다.
리액트의 실행 모델은 대부분 현재 값과 이전 값을 비교하여 동작합니다. 이는 컴포넌트 내부와 useEffect
, useMemo
, useCallback
과 같은 훅에서 발생합니다.
아래와 같은 컴포넌트가 있다고 가정해 보겠습니다.
function MyApp() {
const [count, setCount] = useState(0);
return <Counter count={count} />;
}
Counter
컴포넌트는 count
변수가 변경되면 리렌더됩니다. count
가 변경될 때 어떠한 effect([역주] useEffect 훅에 넘긴 함수를 effect라고 부릅니다)가 실행되기를 원한다고 가정해 봅시다. 아래처럼 useEffect
훅을 사용할 수 있을 것입니다.
function MyApp() {
const [count, setCount] = useState(0);
useEffect(() => {
console.log(count);
}, [count]);
return <Counter count={count} />;
}
count
를 useEffect
훅의 의존성 배열에 추가했기 때문에 effect는 count
가 변경될 때마다 재실행될 것입니다.
이 모델을 사용하면 많은 리액트 개발자들은 컴포넌트가 너무 많이 리렌더되거나 훅이 너무 많이 재실행(때로는 무한히!)된다는 동일한 문제에 직면하게 됩니다.
RFC에 훌륭한 예시가 있기 때문에 이를 그대로 사용하도록 하겠습니다! 먼저 컴포넌트에 text
라는 상태가 있고 SendMessage
를 위한 또 다른 버튼 컴포넌트가 있는 채팅앱을 가정해보겠습니다.
function Chat() {
const [text, setText] = useState("");
const onClick = () => {
sendMessage(text);
};
return <SendButton onClick={onClick} />;
}
문제는 text
가 변경될 때마다, onClick
함수가 재생성된다는 것입니다. SendButton
에 전달된 이전의 onClick
함수와 참조가 동일하지 않으므로 모든 키 입력마다 SendButton
을 쉽게 리렌더링할 수 있습니다.
useEffect
를 너무 자주 실행하는 예시를 살펴보겠습니다. 이 예시는 리액트 코어팀 소속의 Dan Abramov의 트윗에서 가져온 예시입니다. 여기에는 route.url
이 바뀔 때마다 페이지 방문을 로깅하는 effect가 있습니다.
function Page({ route, currentUser }) {
useEffect(() => {
logAnalytics("visit_page", route.url, currentUser.name);
}, [route.url, currentUser.name]);
}
사용자의 이름이 업데이트될 때에도 페이지 방문을 기록하는데, 이는 원하지 않는 동작 입니다. currentUser.name
을 의존성 배열에서 제거할 수도 있습니다. 하지만 이는 리액트에서 권장되지 않습니다. 만약 의존성 배열이 effect 함수 내부의 모든 의존을 반영하지 않는다면 오래된 클로저(stale closures)와 추적하기 어려운 버그가 발생합니다. 이는 리액트 코어팀이 강력하게 권장하는 react-hooks
ESLint 플러그인에 "exhaustive deps" 룰이 있을 정도로 중요합니다.
서문이 길었습니다. 여기까지 같이 따라오셨다면 좋습니다! 드디어 useEvent
에 대해 이야기하고자 합니다. 이 새로운 훅은 의존에 따라 새로운 함수를 만들지 않고도 함수에 대한 안정적인 참조를 보장하기 위해 작성되었습니다.
백문이 불여일견입니다. 앞서 사용했던 예시인 너무 많이 리렌더링 되는 SendButton
을 가진 채팅 앱으로 돌아가 봅시다. 만약 useEvent
가 있다면 클릭 핸들러를 감싸, text
가 변경되더라도 참조가 변경되지 않는 함수로 만들 수 있을 것입니다.
function Chat() {
const [text, setText] = useState("");
const onClick = useEvent(() => {
sendMessage(text);
});
return <SendButton onClick={onClick} />;
}
이제 onClick
은 렌더링 될 때마다 새로 생성되는 대신 항상 같은 함수를 참조할 것입니다. 따라서 SendButton
이 계속 리렌더링 되는 일이 없을 것입니다.
다음 예시였던 페이지 방문 로거도 살펴봅시다.
function Page({ route, currentUser }) {
const logVisit = useEvent((pageUrl) => {
logAnalytics("visit_page", pageUrl, currentUser.name);
});
useEffect(() => {
logVisit(route.url);
}, [route.url]);
}
이제 안정적인 logVisit
함수를 만들었습니다. currentUser.name
을 useEffect
함수의 본문에서 제거하고 route.url
이 변경될 때에만 effect를 실행시킬 수 있습니다.
useEvent
훅에 대한 저의 초기 반응은 "허, useEvent
라니 대체 무슨 의미야?"였습니다. 다른 많은 사람들처럼 저 또한 훅의 이름에 동의할 수 없습니다. 하지만 그건 차치하고, 이 훅은 지난 몇 년 동안 effect의 의존성과 씨름하며 겪었던 고생을 많이 덜어줄 것입니다. 전반적으로 리액트 생태계에 큰 도움이 될 것이라고 생각합니다.
useEvent
훅은 만병통치약이 아닙니다. useEvent는 리액트에 또 다른 개념을 추가합니다. 또한 리액트가 진정한 반응성이 아니라는 사실도 변함없습니다. 진정한 반응성 프레임워크인 SolidJS 예시로 얼마나 간단히 로거를 만들 수 있는지 빠르게 살펴보겠습니다.
function Page(props) {
createEffect(() => {
logAnalytics(
"visit_page",
props.route.url,
untrack(() => props.currentUser.name)
);
});
}
참고사항: 저는 SolidJS docs 팀에 속해있기 때문에 SolidJs를 선호합니다. 여전히 저는 SolidJs가 더 간단하다고 생각합니다. effect의 의존성인 props.route.url
과 props.currentUser.name
은 자동으로 추적됩니다. "추적 해제" 하기 위해서 Solid는 untrack
함수를 제공합니다. 위 코드는 props.route.url
이 변경될 때에만 실행되나 사용자 이름에 대해 클로저를 갖고 있습니다.
This hook is not yet released and its detailed functionality may still undergo https://drivemad2.io/ changes.
와, React Hooks에 관한 이 기사는 정말 놀랍습니다! 웹 개발 게임에서 새로운 차원을 연 것 같은 느낌이 듭니다. 그것은 Slope Game의 마지막 경사면을 정복하는 것과 거의 같습니다. 끝까지 도달해야 하는 중독성 있는 온라인 게임 아시죠? 이번에는 가상 절벽에서 떨어지지 않으려고 노력하는 대신 멋진 것을 만들고 있습니다!
https://slopegameio.github.io/
The new useEvent hook in React seems promising for handling issues with excessive re-renders and stale closures. It's like having a steady game plan in Retro Bowl—you avoid unnecessary changes and keep your setup efficient. Looking forward to seeing how it simplifies our React code! https://retrobowl-game.io/
Every morning feels like a new adventure when I tackle the daily https://www.nytimes.com/games/wordle/index.html challenge.
This article dives into React’s upcoming useEvent
hook, explaining its potential to tackle issues with excessive re-renders and stale closures. If you've ever wrestled with endless useEffect
calls, this new hook could be your hero. Not yet released, but promising! Oh, and by the way, if you want to Google more about it, the real MVP is just a browser tab away. Trust me—worth a quick search!
https://www.google.com/
Your article is a tapestry of wisdom, intricately woven with threads of insight https://pokemoninfinitefusion.io and understanding. Each strand contributes to the vibrant mosaic of knowledge, leaving me in awe of the craftsmanship and dedication you have poured into its creation. I extend my sincerest appreciation for the tapestry of wisdom you have shared.