처음 찾아본 코드로는

useEffect(() => {
  document.body.style.overflow = 'hidden';
  return () => {
    document.body.style.overflow = 'unset';
  };
}, []);

을 사용했는데

 

문제점은 스크롤바가 사라지면서 레이아웃이 비틸렸다 다시 돌아왔다 한다는 것

상당히 거슬려서 새로운 방법을 찾아봤다.

 

 

// utils/modal.ts

/**
 * 스크롤을 방지하고 현재 위치를 반환한다.
 * @returns {number} 현재 스크롤 위치
 */
export const preventScroll = (): number => {
  const currentScrollY = window.scrollY;
  document.body.style.position = "fixed";
  document.body.style.width = "100%";
  document.body.style.top = `-${currentScrollY}px`; // 현재 스크롤 위치
  document.body.style.overflowY = "scroll";
  return currentScrollY;
};

/**
 * 스크롤을 허용하고, 스크롤 방지 함수에서 반환된 위치로 이동한다.
 * @param prevScrollY 스크롤 방지 함수에서 반환된 스크롤 위치
 */
export const allowScroll = (prevScrollY: number) => {
  document.body.style.position = "";
  document.body.style.width = "";
  document.body.style.top = "";
  document.body.style.overflowY = "";
  window.scrollTo(0, prevScrollY);
};
"use client";

import { deleteUser } from "@/actions/auth";
import { ErrorDisplay } from "@/components/ErrorDisplay";
import { Input } from "@/components/Input";
import { Button } from "@/components/ui/Button/Button";
import Modal from "@/components/ui/Modal";
import convertAuthSupabaseErrorToKorean from "@/error/convertAuthSupabaseErrorToKorean";
import logout from "@/utils/auth/logout";
import { AuthError } from "@supabase/supabase-js";
import { useEffect, useState } from "react";

const CHECK_TEXT = "탈퇴하겠습니다";

export default function DeleteUserModalPage() {
  const [valid, setValid] = useState(false);
  const handleCheckText = (e: React.ChangeEvent<HTMLInputElement>) => {
    setValid(e.target.value === CHECK_TEXT);
  };
  const [error, setError] = useState<AuthError | null>(null);
  const [unexpectedError, setUnexpectedError] = useState<Error | null>(null);

  useEffect(() => {
    if (unexpectedError) {
      throw unexpectedError;
    }
  }, [unexpectedError]);

  const handleDeleteUser = async () => {
    if (!valid) return;

    try {
      const { success, error } = await deleteUser();
      if (!success) {
        setError(error || null);
      } else {
        logout();
      }
    } catch (error) {
      setUnexpectedError(error as Error);
    }
  };

  return (
    <>
      <Modal>
        <Modal.Header>회원 탈퇴</Modal.Header>
        <Modal.Content className="p-4">
          <ErrorDisplay
            message={
              convertAuthSupabaseErrorToKorean(error?.code) || error?.message
            }
          />
          <p>회원 탈퇴 시 모든 데이터가 삭제됩니다.</p>
          <p className="mb-4">
            정말 탈퇴하시겠습니까? 원한다면{" "}
            <span className="font-bold text-red-500">
              &quot;{CHECK_TEXT}&quot;
            </span>{" "}
            를 입력하고 버튼을 눌러주세요.
          </p>
          <Input
            type="text"
            placeholder={CHECK_TEXT}
            onChange={handleCheckText}
          />
        </Modal.Content>
        <Modal.Footer>
          <Button disabled={!valid} onClick={handleDeleteUser}>
            회원 탈퇴
          </Button>
        </Modal.Footer>
      </Modal>
    </>
  );
}

 

위와 같은 유틸 함수를 만들고

useEffect를 통해 구현해주면 완성

이전 방법의 문제점이 개선되었다.

'개발 > NEXTJS' 카테고리의 다른 글

nextjs 쿠키 옵션 설정  (1) 2025.02.16
supabase에서 회원 탈퇴 구현하기  (0) 2025.02.10
error.tsx 사용  (0) 2025.02.10
nextjs 에러 관리  (5) 2025.02.05
사용자 avata image 변경했을 때  (0) 2025.01.31

+ Recent posts