React Joyride로 프로덕트 투어 기능 구현하기

Youngeui Hong·2024년 2월 6일
1
post-custom-banner

👋🏻 들어가며

최근 포트폴리오 사이트를 만들면서 고민이 됐던 지점은 "어떻게 하면 프로젝트에서 구현한 기능들을 최대한 풍부하게 보여드릴 수 있을까?"였다.

라이브 데모 링크를 첨부한다 하더라도, 우리 사이트를 처음 이용하는 분이라면 어디를 어떻게 눌러야 작동하는지 알기 어려울 것이기 때문이다.

특히 실제 서비스의 경우 정해진 조건들이 맞아야 제대로 기능이 동작하기 때문에, DB에 적절한 데이터가 없다면 사실상 메인 페이지밖에 볼 수 없는 상황이 되어버리는 것이다.

그래서 생각난 것이 바로 프로덕트 투어 기능이었다.

🚗 React Joyride

리액트에서 프로덕트 투어 기능을 구현할 때 많이 사용되는 라이브러리로는 React Joyride, intro.js, reacttour 등이 있었다.

우선 이번에는 가장 많이 사용되고, 제일 최근까지 업데이트가 이루어진 React Joyride로 프로덕트 투어 기능을 구현해보았다.

React Joyride를 사용해보니 불편한 점이 몇 가지 있었는데, 이 글을 쓰면서 다른 라이브러리들을 다시 살펴보다보니 다음에는 intro.js와 같은 다른 라이브러리를 사용해봐도 괜찮겠다는 생각이 든다.

React Joyride의 어떤 점이 좋았고, 아쉬웠는지는 아래에서 살펴보자.

🛠 Next.js에서 React Joyride 사용하기

React Joyride는 ssr이 지원되지 않아서 아래와 같이 dynamic import를 해서 사용했다.

그리고 페이지별로 Joyride 컴포넌트를 넣어야 하는데, 동일한 기본 옵션을 매 페이지마다 넣는 것은 번거로울 듯하여 아래와 같이 ProductTour 컴포넌트를 따로 만들었다.

import dynamic from "next/dynamic";
import { Props } from "react-joyride";
import TourTooltip from "@/components/product-tour/TourTooltip";

const JoyRide = dynamic(() => import("react-joyride"), { ssr: false });

export default function ProductTour(props: Props) {
  return (
    <JoyRide
      showProgress={true}
      continuous={true}
      spotlightClicks={true}
      tooltipComponent={TourTooltip}
      styles={{
        options: {
          zIndex: 10000,
        },
      }}
      {...props}
    />
  );
}

📝 step 작성하기

프로덕트 투어 영역과 순서를 설정하는 방법은 꽤 간단했다.

steps props에 내가 설명하고자 하는 컴포넌트의 css 선택자(target)와 툴팁에 넣을 내용(content)만 작성해주면 됐다.

필수 항목인 targetcontent 외에도 placement를 사용해서 툴팁의 위치를 정하는 등 변경할 수 있는 옵션들이 꽤 있었다.

<ProductTour
  run={true}
  callback={callback}
  steps={[
    {
      target: "#fan-meeting-photo-carousel",
      content:
      "함께 찍은 사진과 녹화된 팬미팅 영상을 다운로드 및 공유할 수 있어요.",
      disableBeacon: true,
      placement: "left",
    },
    {
      target: "#end-fanmeeting-page",
      content: "자! 이제 돌돌밋을 즐기러 가볼까요? 🚀",
      disableBeacon: true,
      placement: "center",
    },
  ]}
  />

🎨 Tooltip 컴포넌트 커스텀하기

다른 라이브러리들에 비해 React Joyride는 커스텀을 안 해도 기본 디자인이 깔끔하고 예쁜 편이었다.

하지만 마우스를 올렸을 때 버튼 테두리가 검정색으로 두껍게 표시되는 등 몇 가지 걸리는 부분들이 있어서 Tooltip 컴포넌트를 커스텀하기로 했다.

아래와 같이 TooltipRenderProps를 props로 받는 컴포넌트를 만들고, 이 컴포넌트롤 JoyRidetooltipComponent props로 전달해주었다.

import { Box, Button, Stack, Typography } from "@mui/material";
import type { TooltipRenderProps } from "react-joyride/src/types/components";

export default function TourTooltip({
  step,
  index,
  continuous,
  backProps,
  primaryProps,
  closeProps,
}: TooltipRenderProps) {
  return (
    <Stack
      direction={"column"}
      sx={{ backgroundColor: "#FFFFFF", borderRadius: 2, p: 2 }}
      spacing={1}
    >
      <Box sx={{ py: 3, px: 1 }}>
        <Typography sx={{ textAlign: "center", fontSize: 15 }}>
          {step.content}
        </Typography>
      </Box>
      <Stack
        direction={"row"}
        justifyContent={index === 0 ? "flex-end" : "space-between"}
      >
        {index > 0 && (
          <Button {...backProps} variant={"outlined"}>
            Back
          </Button>
        )}
        {!step.hideFooter && continuous && (
          <Button {...primaryProps} variant={"contained"}>
            Next
          </Button>
        )}
        {!step.hideFooter && !continuous && (
          <Button {...closeProps}>Close</Button>
        )}
      </Stack>
    </Stack>
  );
}

📣 callback 활용하기

프로덕트 투어 기능을 구현하면서 state를 변경하거나, url을 이동해야 하는 경우가 있었다. 이를 위해 JoyRide 컴포넌트의 callback props를 활용했다.

버튼을 누를 때마다 콜백 함수가 실행되는데, 콜백함수의 인자로 전달되는 CallBackProps에는 현재 버튼이 눌러진 스텝에 대한 정보(현재 툴팁이 보이는 상태인지, 종료된 상태인지, 몇 번째 단계인지 등등)가 담겨 있다.

이를 활용해서 내가 원하는 시점에 state를 변경해서 팝업을 띄우거나, url을 이동할 수 있었다.

intro.js의 경우 onStart, onChange, onComplete 등 콜백 함수가 세분화되어 있는 점이 상대적으로 좋아보였다. 콜백 함수를 다뤄야 할 일이 많다면 이 라이브러리를 써봐도 괜찮을 것 같았다.

  const productTourCallback = (data: CallBackProps) => {
    const { type, step, lifecycle } = data;

    // state 변경
    if (step.target === "#subtitle-bar" && lifecycle === "tooltip") {
      setEndSoon(true);
    }

    // url 이동
    if (type === "tour:end") {
      window.location.href = "/end-fanmeeting/user/3";
    }
  };

👏🏻 결과물

그렇게 해서 완성된 최종 결과물은 아래와 같다.

실제 서비스의 경우 영상통화 상대가 접속해 있어야 영상통화방으로 넘어갈 수 있어서 사실상 메인 페이지 밖에 볼 수 없는 상태였는데, 프로덕트 투어 기능을 도입해서 팬미팅의 시작부터 종료까지 주요 기능을 전반적으로 훑어볼 수 있는 상태가 되어서 좋았다.

post-custom-banner

0개의 댓글