useInjectedProps

2024. 3. 20. 14:58코반주반

컴포넌트의 Props를 일부 오버라이드하면서 인터페이스를 바꾸고, 컴포넌트가 동일한 ref를 갖게(re-render 가능하게) 해주는 훅을 만들어보자.

 

Implementation

export default function useInjectedProps<
  C extends React.FC<any>,
  I extends Partial<Record<keyof ComponentProps<C>, any>>,
>(_Component: C, injectedProps: I) {
  // 훅의 인자로 받은 컴포넌트를 저장합니다.
  const Component = useRef<any>(_Component);

  // 상태 변경이 일어나면서 컴포넌트 호출이 일어날 경우 injectedProps가 컴포넌트로 자연스럽게 주입 될 수 있게 합니다.
  Component.current = (props: Omit<ComponentProps<C>, keyof I>) => {
    return <_Component {...props} {...injectedProps} />;
  };

  // 컴포넌트의 ref를 고정시키기 위해 빈 배열의 useCallback 훅을 사용합니다.
  return useCallback((props) => Component.current(props), []) as React.FC<
    Omit<ComponentProps<C>, keyof I>
  >;
}

 

Use Case

type ButtonProps = {
  onClick: Function;
};

const Button = ({ onClick }: ButtonProps) => {
  return <button onClick={onClick}>Hello World</button>;
};

type ButtonWithTextProps = ButtonProps & {
  text: string;
};

const ButtonWithText = ({ onClick, text }: ButtonWithTextProps) => {
  return <button onClick={onClick}>{text}</button>;
};

const Renderer = ({ RenderButton }: { RenderButton: React.FC<ButtonProps> }) => {
  return <RenderButton onClick={() => alert('Hello World')} />;
};

const UseCase = () => {
  const RenderButton = useInjectedProps(ButtonWithText, {
    text: 'World Hello',
  });
  
  return <Renderer RenderButton={RenderButton} />;
};

//===> <button>World Hello</button>

 

 

reference

https://github.com/reactjs/rfcs/blob/useevent/text/0000-useevent.md