useAtomEffect
useAtomEffect
는 atomEffect를 사용하여 아톰이나 props의 변화에 반응하는 사이드 이펙트를 실행합니다.
effectFn은 의존하는 아톰이 변경되거나 effectFn 자체가 변경될 때마다 다시 실행됩니다. effectFn이 컴포넌트 내부에서 정의된 함수라면 반드시 메모이제이션해야 합니다.
⚠️ 주의: 추가적인 atomEffect 재계산을 피하기 위해 항상 안정적인 버전의 useMemo와 useCallback을 사용하는 것을 권장합니다. useMemo를 성능 최적화를 위해 사용할 수는 있지만, 의미적 보장을 위해 사용해서는 안 됩니다. 향후 React는 메모리 확보를 위해 이전에 메모이제이션된 값을 "잊어버리고" 다음 렌더링 시 다시 계산할 수 있습니다. 예를 들어, 화면 밖 컴포넌트를 위해 메모리를 확보하는 경우가 있습니다.
import { useMemoOne as useStableMemo } from 'use-memo-one'import { useAtomValue } from 'jotai/react'import { atomEffect } from 'jotai-effect'type EffectFn = Parameters<typeof atomEffect>[0]export function useAtomEffect(effectFn: EffectFn) {useAtomValue(useStableMemo(() => atomEffect(effectFn), [effectFn]))}
예제 사용법
import { useCallbackOne as useStableCallback } from 'use-memo-one'import { atom, useAtom } from 'jotai'import { atomFamily } from 'jotai/utils'import { useAtomEffect } from './useAtomEffect'const channelSubscriptionAtomFamily = atomFamily<Channel>((channelId: string) => {return atom(new Channel(channelId))},)const messagesAtom = atom<Message[]>([])function Messages({ channelId }: { channelId: string }) {const [messages] = useAtom(messagesAtom)useAtomEffect(useStableCallback((get, set) => {const channel = get(channelSubscriptionAtomFamily(channelId))const unsubscribe = channel.subscribe((message) => {set(messagesAtom, (prev) => [...prev, message])})return unsubscribe},[channelId],),)return (<><h1>총 {messages.length}개의 메시지가 있습니다</h1><hr />{messages.map((message) => (<div key={message.id}>{message.text}</div>))}</>)}