상세 컨텐츠

본문 제목

React forwardRef - (feat. 공통 팝업)

React

by 일단두잇 2023. 2. 1. 22:04

본문

반응형

 

forwardRef는 component간 ref를 전달하기 위해 사용하는 Function 입니다.

React에서는 ref를 props로 직접전달하지 않고 fowardRef를 통하여 해당 ref를 전달합니다.

 


그러면, 일반적으로 사용될 수 있는 공통 팝업을 통해 구현해보겠습니다.

 

팝업은,

- Transition 효과가 적용되어야 하며

- close 함수를 제공하여햐 합니다.

 

1. forwardRef를 사용하여 component 생성

 

- 인자로 props, ref 전달받는 component를 생성합니다.

- ref는 해당 팝업의 close함수를 "상위 컴포넌트에서 사용하고자 참조하기 위해서" 사용합니다.

// 제공하기 원하는 함수 정의
interface ISlidePopupRef {
  close(): void;
}

// props type 정의
type Props = {
  title: string; // 팝업 제목
  // Event 정의
  onExit?(): void; 
  onExited?(): void;
  onEntered?(): void;
  onClickBack?(): void;
  children: JSX.Element; // 팝업 content
};

const Slidepopup = React.forwardRef<ISlidePopupRef, Props>(
  ({ title, onExit, onEntered, onExited, onClickBack, children }, ref)
 

2. useImperativeHanle hook : 상위 컴포넌트에서 제공하고자 하는 함수 정의

const [isPopupShow, setPopupShow] = useState(true);
const close = () => {
      setPopupShow(false);
      onClickBack?.();
};
useImperativeHandle(ref, () => ({ close }));
 

3. propTypes 정의 : 전달하는 prop의 type을 정의합니다.

- 필수가 아니기 때문에 오류가 발생하지는 않지만, isRequired나 type 오류 방지를 위해 작성합니다.

SlidePopup.propTypes = {
  title: PropTypes.string.isRequired,
  onExit: PropTypes.func,
  onExited: PropTypes.func,
  onEntered: PropTypes.func,
  onClickBack: PropTypes.func,
  children: PropTypes.element.isRequired,
  ref: PropTypes.func,
};
 

 

4. 상위 컴포넌트에서 사용

- useRef를 통해 참조값 설정

- 전달받은 ref의 close function 호출

const popupRef = React.useRef<{ close: () => void }>(null);
....
<SlidePopup ref={popupRef} title="팝업 Todo">
  <ListStyled>
      <li>할일1</li>
      <li>할일2</li>
      <button onClick={()=>popupRef.current.close()}>닫기</button>
   </ListStyled>
</SlidePopup>
 

이처럼 forwardRef를 사용하면 ref를 전달하여 컴포넌트안의 element를 참조하거나

해당 컴포넌트의 특정 함수를 호출할 수 있습니다.

 

※ 최종 팝업 코드

import React, { useImperativeHandle, useRef, useState } from 'react';
import { CSSTransition } from 'react-transition-group';

import PropTypes from 'prop-types';

export interface ISlidePopupRef {
  close(): void;
}

type Props = {
  title: string;
  onExit?(): void;
  onExited?(): void;
  onEntered?(): void;
  onClickBack?(): void;
  pageBottom?: JSX.Element;
  children: JSX.Element;
};

const SlidePopup = React.forwardRef<ISlidePopupRef, Props>(
  ({ title, onExit, onEntered, onExited, onClickBack, pageBottom, children }, ref) => {
    const nodeRef = useRef(null);
    const [isPopupShow, setPopupShow] = useState(true);

    const close = () => {
      setPopupShow(false);
      onClickBack?.();
    };

    useImperativeHandle(ref, () => ({ close }));

    return (
      <CSSTransition
        appear
        nodeRef={nodeRef}
        in={isPopupShow}
        unmountOnExit
        classNames={'popup-right'}
        timeout={300}
        onEntered={onEntered}
        onExit={onExit}
        onExited={onExited}
      >
        <PageContainer ref={nodeRef}>
          <>
            <TitleContainer>
              <BackBtn onClick={close} />
              <Title>{title}</Title>
            </TitleContainer>
            <PageContent>{children}</PageContent>
          </>
        </PageContainer>
      </CSSTransition>
    );
  }
);
SlidePopup.displayName = 'SlidePopup';

SlidePopup.propTypes = {
  title: PropTypes.string.isRequired,
  onExit: PropTypes.func,
  onExited: PropTypes.func,
  onEntered: PropTypes.func,
  onClickBack: PropTypes.func,
  children: PropTypes.element.isRequired,
  ref: PropTypes.func,
};

export default SlidePopup;
 

 

 

반응형

관련글 더보기

댓글 영역