본문 바로가기
React

[React] 선언적으로 유저 행동 이벤트 추적하기 with React.cloneElement()

by LasBe 2023. 8. 29.
반응형

⚡️ 선언적으로 유저 행동 이벤트 추적하기


최근에 B2C 업무에 투입되며 전반적인 앱 플로우와 곧 제가 하게 될 업무에 대해 설명을 들었습니다.

 

그중 data-driven 한 의사 결정을 위해 유저 이벤트 추적 툴을 도입한 상태였고,
정해주는 이벤트에 추적 기능을 붙이는 업무도 하게 될 것이라는 말씀을 들었습니다.

 

그러면서 예시 코드를 보여주셨는데 예시로 다음과 같이 버튼 클릭 이벤트 핸들러 함수 안에
추적 툴에서 제공한 함수를 이어붙인 모양이었습니다.

const handleClickSignUp = () => {
  이벤트_추적();
  // ~~~

    회원가입();
  // ~~~
}

이러한 방식은 하나의 함수에 두가지 이상의 기능이 담겨 가독성을 해치고 유지보수가 여러워 질 것이 뻔합니다.

 

그렇다면 기능을 분리하고 선언적으로 사용할 수 있도록 컴포넌트화를 하면 좋겠는데 순간 예전에 인상 깊게 봤던 글이 떠올랐습니다.

 

선언적인 코드 작성하기

선언적인 코드, 토스 프론트엔드 챕터는 어떻게 생각을 하고 있을까요?

toss.tech

토스 프론트엔드 개발자 분이 토스 기술 블로그에 작성하신 글인데
그중에서도 위와 같은 방법을 비슷하게 구현해서 써먹을 수 있겠다 싶었습니다.

 

그런데 실제로 구현된 코드는 나와있지 않고 아이디어만 얻었을 뿐이어서
리액트의 새로운 기능을 찾아보며 개념을 비슷하게 따라 해봤습니다.


📌 Event 가로채기

우선 자식 요소의 이벤트를 가져다가 어떤 행동을 취하려면 부모 컴포넌트에서 그 이벤트를 사용할 수 있어야 합니다.

 

리액트에서는 자식 요소를 부모 요소에서 사용할 수 있고, 사용하는 방법은 다음과 같습니다.

type PropsType = {
  children: React.ReactElement;
};

const ParentConponent = ({ children }: PropsType) => {
  console.log("children => ", children);
  return children;
};

export const ChildrenComponent = () => {
  return (
    <ParentConponent>
      <button onClick={() => console.log("클릭 이벤트 발생")}>버튼</button>
    </ParentConponent>
  );
};

 

이 컴포넌트들이 렌더링 된 후 콘솔에 찍힌 children은 다음과 같습니다.

자세히 들여다보면 children.props 안에 onClick() 함수가 존재하는 것을 확인할 수 있습니다.

 

const { onClick } = children.props;

그렇다는 것은 위와 같이 자식 요소에서 이벤트 함수를 꺼내 재정의 할 수 있다는 것을 의미합니다.

 

그럼 이제 재정의 한 함수를 children에 다시 적용해 주면 되겠죠?


📌 React.cloneElement()

React.cloneElement 함수는 React 라이브러리에서 제공하는 함수 중 하나로,
기존의 React 엘리먼트를 복제하면서 일부 속성을 수정하거나 새로운 속성을 추가하는 데 사용됩니다.

 

이 함수는 React 엘리먼트를 더 동적으로 조작하고 확장할 수 있는 방법을 제공합니다.

React.cloneElement(element, [props], [...children])
  • element
    복제할 기존 React 엘리먼트입니다.
  • props (선택 사항)
    새로운 속성 객체로, 기존 엘리먼트의 속성을 수정하거나 추가할 수 있습니다.
  • children (선택 사항)
    새로운 자식 엘리먼트를 지정할 수 있습니다. 기존 엘리먼트의 자식 엘리먼트를 대체하거나 추가할 수 있습니다.

 

그럼 cloneElement를 이용해 자식 요소의 이벤트를 재정의하고 적용하는 코드는 다음과 같습니다.

 

import React, { cloneElement } from "react";

type PropsType = {
  params: string;
  children: React.ReactElement<{ onClick: () => void }>;
};

const ClickEventLogging = ({ params, children }: PropsType) => {
  const overrideClickEvent = () => {
    const { onClick } = children.props;
    console.log(children);
    console.log("Logging: ", params);
    onClick();
  };

  return cloneElement(children, { onClick: overrideClickEvent });
};

export default function App() {
  return (
    <div>
      <ClickEventLogging params="버튼 클릭">
        <button onClick={() => console.log("버튼 클릭 이벤트 발생")}>
          클릭 후 콘솔을 확인해 주세요
        </button>
      </ClickEventLogging>
    </div>
  );
}

이렇게 하면 간단하고 효율적으로 분리해 유저 이벤트를 재정의 할 수 있습니다.

 

또한 여기서 아주 조금만 수정한다면 효과적인 로깅과 유저 행동을 추적하는 컴포넌트를 제작할 수 있게 됩니다.

 

그럼 이번에 찾아본 내용들을 토대로 실제 서비스에 적용해 봐야겠습니다.

반응형

댓글


오픈 채팅