사툰사툰

useConditionalEffect

의존성 및 조건 기반으로 useEffect 동작 여부를 결정하는 훅입니다

4

import { type DependencyList, type EffectCallback, useCallback, useEffect, useRef } from 'react';

/**
 * @description useEffect를 좀 더 효과적으로 제어할 수 있는 훅입니다
 * @reference https://github.com/toss/react-simplikit/blob/main/src/hooks/useConditionalEffect/useConditionalEffect.ts
 *
 * @param effect
 * @param deps
 * @param condition (prevDeps: T | undefined, currentDeps: T) => boolean
 *  - 이전 및 현재 의존성을 기반으로 효과를 실행할지 결정하는 함수예요.
 *  - 초기 렌더링 시, prevDeps는 undefined일 거예요. condition 함수는 이 경우를 처리해야 해요.
 *  - 초기 렌더링 시 효과를 실행하려면, prevDeps가 undefined일 때 true를 반환하면 돼요.
 *  - 초기 렌더링 시 효과를 실행하고 싶지 않다면, prevDeps가 undefined일 때 false를 반환하면 돼요.
 */
export function useConditionalEffect<T extends DependencyList>(
  effect: EffectCallback,
  deps: T,
  condition: (prevDeps: T | undefined, currentDeps: T) => boolean,
): void {
  const prevDepsRef = useRef<T | undefined>(undefined);
  const memoizedCondition = useCallback(condition, deps);

  if (deps.length === 0) {
    console.warn(
      'useConditionalEffect received an empty dependency array. ' +
        'This may indicate missing dependencies and could lead to unexpected behavior.',
    );
  }

  const shouldRun = memoizedCondition(prevDepsRef.current, deps);

  useEffect(() => {
    if (shouldRun) {
      const cleanup = effect();
      prevDepsRef.current = deps;
      return cleanup;
    }

    prevDepsRef.current = deps;
  }, deps);
}