[Next.js + Typescript] 컴포넌트 자체를 넘겨받아 렌더링하기

2024. 12. 17. 14:01
반응형

 

'공유하기' 동작을 하는 버튼이 여기저기서 쓰여 공통 컴포넌트로 만들었는데,

이게 때에 따라 [버튼]이기도, [아이콘]이기도 해야했다.

 

아래와 같이 컴포넌트<Button>, <Icon> 자체를 넘겨받아 렌더링해줄 수 있도록 했다.

 

 

import { usePathname, useSearchParams } from 'next/navigation';
import Button, { ButtonProps } from '@/components/commons/Button';
import { toast } from 'react-toastify';
import { ComponentProps, ElementType, ReactNode } from 'react';

type Props<T extends ElementType> = {
  as?: T; // 동적으로 렌더링할 컴포넌트
  children?: ReactNode;
  successMsg?: string;
  errorMsg?: string;
} & ComponentProps<T>;

/**
 *
 * 현재 url을 복사하는 컴포넌트
 *
 * */
const CopyComponent = <T extends ElementType>({
  as = Button,
  children,
  successMsg = 'url이 복사되었습니다.',
  errorMsg = '오류가 발생했습니다.',
  ...props
}: Props<T>) => {
  const pathname = usePathname();
  const searchParams = useSearchParams();

  const Component = as;

  const handleCopy = async () => {
    try {
      const queryString = searchParams.toString();
      const fullUrl = `${window.location.origin}${pathname}${
        queryString ? `?${queryString}` : ''
      }`;
      await navigator.clipboard.writeText(fullUrl);
      toast.success(successMsg);
    } catch (error) {
      toast.error(errorMsg);
    }
  };

  return (
    <Component {...props} onClick={handleCopy}>
      {children}
    </Component>
  );
};

export default CopyComponent;

 

// 버튼형태로 가져다 사용할 때
<CopyComponent as={Button} $rightIcon="share" $variant="outlinePrimary">
  공유하기
</CopyComponent>



// 아이콘형태로 가져다 사용할 때
<CopyComponent as={Icon} name="share" />

 

 

버튼으로 사용할 때와 아이콘으로 사용할 때

 

반응형

BELATED ARTICLES

more