고윤태의 개발 블로그

누구나 접근하기 쉽지만 얻어 가는 것이 있는 글을 쓰기 위해 노력 중입니다.

개발

사용자의 결정을 도와주는 useComfirm custom hook

고윤태 2024. 4. 1. 15:29
안녕하세요 이번에 작성하게 될 내용은 제가 react-native에서 개발한 useComfirm custom hook에 대해 공유하고자 글을 작성하게 되었습니다.

💻 개발 환경

React-native(expo) + TypeScript로 진행되었습니다.

🧐 구현하게 된 계기

React Native 앱 개발 과정에서 흔히 마주치는 UI 구성 요소인 모달과 오버레이를 더욱 스마트하게 관리할 수 있는 방법에 대해 이야기해보려 합니다. 특히, 반복되는 Dialog 생성 코드의 중복을 줄이기 위해 커스텀 훅을 만들어 관리하는 경험을 공유하려고 합니다.

 

 

특히나 현재 저희 서비스에는 삭제/닫기를 통해 사용자에게 확인을 하는 Flow가 다수 존재했습니다.

사용자에게 선택을 요구하는 다양한 상황에서 Dialog 컴포넌트를 자주 사용하게 되었습니다. 처음에는 각 시나리오에 맞춰 Dialog 생성 코드를 반복해서 작성했습니다. 이 과정에서 코드의 중복이 불가피하게 발생하고, 유지 보수의 효율성이 떨어진다는 문제에 직면했습니다.

 

React Native useModal 구현하기

https://yun-tech-diary.tistory.com/entry/React-Native-useModal-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0

 

React Native useModal 구현하기

안녕하세요 이번에 회사 앱에 flow를 깊게 확인하기 위해 이것저것 해보는 와중 제 눈에 띈 것이 하나 있습니다. 바로 Modal 입니다. Modal은 앱에서 흔히 볼 수 있는 UI입니다. Modal을 사용하는 곳에

yun-tech-diary.tistory.com

 

React Native useOverlay를 만들어 리팩토링 하기 이 글은 진짜 떠야 해

https://yun-tech-diary.tistory.com/entry/React-Native-useOverlay%EB%A5%BC-%EB%A7%8C%EB%93%A4%EC%96%B4-%EB%A6%AC%ED%8C%A9%ED%86%A0%EB%A7%81-%ED%95%98%EA%B8%B0-%EC%9D%B4-%EA%B8%80%EC%9D%80-%EC%A7%84%EC%A7%9C-%EB%96%A0%EC%95%BC-%ED%95%B4

 

React Native useOverlay를 만들어 리팩토링 하기 이 글은 진짜 떠야 해

안녕하세요 이번에 작성하게 될 내용은 제가 react-native에서 useOverlay라는 custom hook을 구현한 과정과 어떤 식으로 구현했는지에 대해 글을 작성해 보도록 하겠습니다. 💻 개발 환경 React-native(expo)

yun-tech-diary.tistory.com

 

 

그동안 Dialog를 효율적으로 관리하기 위해 이런 시도들을 했었습니다.

이번에도 새로운 시도를 해볼까 합니다.

🤔 기능 산출 및 개발 계획

정적인 Dialog를 편리하게 사용하기 위해 제가 전에 useOverlay를 구현했었습니다.

이번에 만들 Dialog는 사용자에게 단순 삭제/닫기 의사 결정만 확인하니 정적인 Dialog로서 useOverlay를 활용해서 만들 계획을 세웠습니다.

 

그렇다면 해당 Dialog들에서 유연하게 변경되어야 하는 부분은 무엇일까요?

바로 Dialog의 Title과 Content 내용 또 삭제 버튼을 눌렀을 때 발생할 callback event입니다.

 

 

  • blue : Dialog Title 내용
  • red : Dialog Content 내용
  • yellow : 삭제 버튼 callback event 발생
  • green : Dialog Close

이런 식으로 정리해 볼 수 있습니다.

 

정리한 내용을 바탕으로 개발을 진행해 보겠습니다.

 

👀 Custom hook 개발(CODE)

import Dialog from '../components/ui/Dialog';
import useOverlay from './overlay/useOverlay';

interface DialogContents {
  title?: string;
  content?: string;
}

const useConfirmDeletion = () => {
  const overlay = useOverlay();

  const openDialog = (
    { title, content }: DialogContents,
    onRemoveHandler: () => void
  ) => {
    overlay.open(
      <Dialog isOpened={true}>
        {title && <Dialog.Title title={title} />}
        {content && <Dialog.Content content={content} />}
        <Dialog.Buttons
          buttons={[
            {
              label: '삭제',
              onPressHandler: () => {
                overlay.close();
                onRemoveHandler();
              },
            },
            {
              label: '취소',
              onPressHandler: () => {
                overlay.close();
              },
            },
          ]}
        />
      </Dialog>
    );
  };

  return openDialog;
};

export default useConfirmDeletion;

코드 설명

  • useOverlay 훅 사용: 애플리케이션의 다른 부분에서 정의된 useOverlay 훅을 사용하여 다이얼로그 레이어를 관리합니다. 이는 다이얼로그가 애플리케이션의 다른 UI 요소 위에 올바르게 표시되도록 합니다.
  • openDialog 함수: openDialog는 DialogContents 객체와 삭제를 처리하는 콜백 함수 onRemoveHandler를 인자로 받습니다. DialogContents는 선택적으로 다이얼로그의 title과 content를 정의합니다.
  • 다이얼로그 내용 동적 생성: 전달된 title과 content를 기반으로 다이얼로그 내용을 동적으로 생성합니다. title이나 content가 존재하는 경우에만 해당 섹션이 렌더링 됩니다.
  • 삭제 및 취소 버튼: 사용자에게 제공되는 두 버튼("삭제", "취소")은 사용자가 선택할 수 있는 옵션을 제공합니다. 각 버튼에는 클릭 이벤트 핸들러가 연결되어 있으며, "삭제" 버튼을 클릭하면 onRemoveHandler가 호출되고, "취소" 버튼을 클릭하면 다이얼로그가 닫힙니다.

 완성된 useConfirmDeletion

예제 코드

import React, { useState } from 'react';
import Container from '../components/layout/Container';
import { View } from 'react-native';
import Button from '../components/ui/buttons/Button';
import useConfirmDeletion from '../hooks/useConfirmDeletion';

const Screen = () => {
  const confirmDeletion = useConfirmDeletion();
  const [isOn, setIsOn] = useState(false);

  return (
    <Container>
      <View
        style={{
          width: 100,
          height: 100,
          backgroundColor: isOn ? 'red' : 'blue',
        }}
      ></View>
      <Button
        label='open confirmDeletion'
        onPressHandler={() => {
          confirmDeletion({ title: 'title', content: 'content' }, () => {
            setIsOn(true);
          });
        }}
      />
    </Container>
  );
};

export default Screen;

예제 코드 설명

"open ConfirmDeletion"이라는 Button을 Press 시 useConfirmDeletion hook을 이용하여 Dialog를 사용자에게 노출시킵니다.

"삭제"라는 버튼 클릭 시 isOn이라는 state 값이 변경되어 View로 생성된 Box의 backgroundColor가 blue에서 red로 변경됩니다.

실행 결과

😁 글 작성 후기

오늘도 간단한 custom hook을 들고 왔습니다만 실제로 스크린에서 글 삭제 로직이 있는 곳에서 유용하게 사용 중입니다.

 

 

이 custom hook이 간단하게 구현됐던 이유 중 하나인 제가 이전에 Overlay 계열의 컴포넌트를 손쉽게 관리하기 위해 개발했던 useOverlay를 구현해 놨기 때문인데요 다른 분들도 custom hook을 만들 때 이전에 만들었던 custom hook을 활용해서 더 유용한 custom hook을 만들어 보는 기회를 가져보는 것도 좋은 경험이 될 것 같습니다.