React.js

[React] Framer-motion, HOC 관련 Runtime Error

Chunho 2025. 4. 29. 17:59
import _ from "lodash";

type HOC<T> = (
  WrappedComponent: any // functional or class component 모두 될 수 있다.
) => React.FC<T>;

const MergeMotion = <T = unknown, A = unknown, B = unknown, C = unknown>(
  TargetComponent: React.ComponentType<T>,
  hoc1: HOC<A>,
  hoc2: HOC<B>,
  hoc3?: HOC<C>
): React.FC<T & A & B & C> => {
  return _.flowRight(_.compact([hoc1, hoc2, hoc3]))(TargetComponent);
};

export default MergeMotion;​

빛이 지나가는 이펙트를 주기 위해 여러 컨텐트에서 공통으로 사용되고 있는 Glow 컴포넌트가 있다.
미션 페이지에서 리스트를 뿌려줄 때, 완료해서 보상을 수령 가능한 미션, 완료하지 않은 미션의 애니메이션을 다르게 적용해주었는데, 완료한 미션일 경우 Slide up 애니메이션과 Glow 애니메이션이 동시에 적용되어야 했다.

const withGlow = <T extends {}, P extends GlowProps>(
  WrappedComponent: React.ComponentType<T> // functional or class component 모두 될 수 있다.
): React.FC<T & P> => {
  const SlideUpComponent = (props: T & P) => {
    return (
      <div className={styles.glow_wrapper}>
        <WrappedComponent {...props} />
        <MotionDiv
          initial={glow.initial}
          transition={{
            duration: props.glow?.duration ?? 2,
            delay: props.glow?.delay ?? 0,
            repeat: props.glow?.repeat ?? 0,
            repeatDelay: props.glow?.repeatDelay ?? 0,
          }}
          whileInView={glow.animate}
          viewport={glow.viewport}
          data-light-intensity={props.glow?.hard ? "hard" : "light"}
          data-light-color={props.glow?.dark ? "dark" : "light"}
        />
      </div>
    );
  };
  return SlideUpComponent;
};


위와 같이 고차 컴포넌트(HOC)를 만들어주고 

const ClaimableMissionItem = MergeMotion(MissionItem, withGlow, withSlideUp);​

묶어서 사용하던 중 null 참조 런타임 에러가 발생했다. 

Framer-motion 관련 런타임 에러라고 생각하지 못한 채 디버깅을 하던 중 원인을 찾을 수 있었다.

dataList는 tab의 상태에 따라 동적으로 변경되었는데, Weekly 탭으로 전환될 때 애니메이션이 실행되려고 하지만, 컴포넌트가 아직 완전히 마운트되지 않은 상태에서 애니메이션을 시도하면서 null 참조 에러가 발생하고 있었다.

공통 컴포넌트에서도 물론 null 체크를 해주었지만, deps가 깊어지는 컴포넌트, 공통 컴포넌트 및 HOC를 관리할 때 null체크 및 예외처리를 좀 더 꼼꼼하게 해주어야겠다,,