마이페이지 프로필 수정 with 트러블슈팅

이보아·2024년 7월 31일
0

마이페이지 프로필 수정 구현하기

마이페이지에서 왼쪽 네비게이션과 오른쪽 프로필 수정 영역을 동시에 보여주는 UI 구현 하였다. 이미지를 수정하는 방식은 프로필 이미지를 수정하면 스토리지에 이미지가 업로드되고, 이 이미지의 URL이 생성되어 Users 테이블의 profile_image_url 컬럼에 저장되어 그 URL을 다시 불러오는 방식이였다. 하지만 수정된 프로필 이미지는 오른쪽 프로필 수정 영역에서는 바로 반영되지만, 왼쪽 네비게이션에서는 새로고침을 해야만 적용되는 문제가 발생했다.🥲

원인이 됬던 부분

이 문제는 프로필 이미지 수정 후, 왼쪽 네비게이션에 반영되는 데이터가 즉시 업데이트되지 않아서 발생했던 문제였다. 오른쪽 프로필 수정 영역에서는 state를 통해 즉각 반영되지만, 왼쪽 네비게이션에서는 별도의 state 관리가 이루어지지 않았기때문에 수정된 이미지가 즉각적으로 반영이 안됬던게 원인이였다.

해결 방법

1. 사용자 데이터 업데이트 후, 상태 관리

사용자 데이터 업데이트 후, 상태 관리 프로필 이미지를 업로드하고, 스토리지에 저장된 URL을 Users 테이블에 업데이트한 후, state를 통해 프로필 이미지를 즉시 반영하도록 로직을 수정하였다. setUserData 함수를 사용하여 사용자 데이터를 업데이트하고, 이를 통해 프로필 이미지가 즉시 반영되도록 구현 했다.

// 프로필 이미지 업로드 및 업데이트 함수
const uploadProfileImage = async (file: File | Blob, altText: string) => {
  if (!user) return;
  setUploading(true);
  try {
    const FileName = `profile_${base64Encode(user.id)}.png`;
    const { error: uploadError } = await supabase.storage
      .from("images")
      .upload(`profileImages/${FileName}`, file, { upsert: true });
    if (uploadError) throw uploadError;

    // 업로드한 파일의 public URL 가져오기
    const { data: profileImageUrlData } = await supabase.storage
      .from("images")
      .getPublicUrl(`profileImages/${FileName}`);

    const profileImageUrl = profileImageUrlData.publicUrl;

    if (profileImageUrl) {
      // 데이터베이스에서 사용자의 프로필 이미지 URL 업데이트
      const { error: updateError } = await supabase
        .from("Users")
        .update({ profile_image_url: profileImageUrl })
        .eq("user_id", user.id);
      if (updateError) throw updateError;

      // 데이터베이스 업데이트 후, 프로필 이미지 상태를 새 URL로 변경
      setProfileImage(profileImageUrl);
      setProfileAlt(altText);
      setUserData({ ...userData, profile_image_url: profileImageUrl }); // 사용자 데이터 상태 업데이트
      toast.success("프로필 이미지 업데이트 성공하였습니다.");
    } else {
      throw new Error("프로필 이미지 URL을 얻지 못했습니다.");
    }
  } catch (error) {
    console.error("프로필 이미지 업데이트 중 오류 발생:", error);
    toast.error("프로필 이미지 업데이트가 완료되지 않았습니다.");
  } finally {
    setUploading(false);
  }
};

2. 전역 상태 관리를 위한 useContext 구현

사용자 데이터를 전역에서 관리하기 위해 useContext를 사용하여 상태 관리 로직을 추가했다. 이를 통해, 사용자 데이터가 업데이트될 때마다 필요한 모든 컴포넌트에서 해당 변경 사항을 반영할 수 있게 했다.

import React, { createContext, useContext, useState, useEffect } from "react";
import { createClient } from "@/utils/supabase/client";
import { User } from "@supabase/supabase-js";

interface UserContextType {
  user: User | null;
  userData: any;
  setUserData: (data: any) => void;
  fetchUserData: () => void;
}

const UserContext = createContext<UserContextType | undefined>(undefined);

export const UserProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const [user, setUser] = useState<User | null>(null);
  const [userData, setUserData] = useState<any>(null);
  const supabase = createClient();

  // 사용자 객체 가져옴
  useEffect(() => {
    const fetchUser = async () => {
      const {
        data: { user },
      } = await supabase.auth.getUser();
      setUser(user);
    };
    fetchUser();
  }, [supabase]);

  // 사용자 데이터를 가져옴
  const fetchUserData = async () => {
    if (!user) return;
    const { data, error } = await supabase.from("Users").select("*").eq("user_id", user.id).single();
    if (error) {
      console.error("사용자 데이터 불러오기 실패:", error);
    } else {
      setUserData(data);
    }
  };

  // 사용자 객체가 변경될 때마다 사용자 데이터를 가져옴
  useEffect(() => {
    fetchUserData();
  }, [user]);

  return <UserContext.Provider value={{ user, userData, setUserData, fetchUserData }}>{children}</UserContext.Provider>;
};

export const useUser = () => {
  const context = useContext(UserContext);
  if (context === undefined) {
    throw new Error("useUser는 UserProvider 내에서만 사용될 수 있습니다.");
  }
  return context;
};

3. 왼쪽 네비게이션 컴포넌트에서 상태 관리

userData가 업데이트될 때마다 왼쪽 네비게이션의 프로필 이미지가 즉시 반영되도록 상태 관리 로직을 추가했다.

const { userData } = useUser();
const [loading, setLoading] = useState(true);

useEffect(() => {
  if (userData) {
    setLoading(false);
  }
}, [userData]);

마무리

같은 데이터를 동시에 보여줄때는 조금 더 고민하고 코드를 작성해야겠다고 생각했다.

profile
매일매일 틀깨기

0개의 댓글