■ 프로필 불러오기, 프로필 이미지 수정
(1) superbase storage 에 'avatars' 버켓을 생성하고 policies → avatars →New policy → 모든 작업 체크 해서 정책 설정
(2) avatars 버켓에 default-profile.jpg 파일 업로드
(3) vscode 에서 getPublicUrl 메서드를 사용해 avatars 버킷에 있는 기본이미지 불러오기
const { data } = supabase.storage.from('avatars').getPublicUrl('default-profile.jpg');
(4) 파일 업로드 코드 작성
const handleFileInputChange = async (e) => {
// 타입이 file인 input 가져오기
const files = e.target.files;
// files 는 데이터 타입이 항상 배열형태 -> 배열 구조분해할당으로 파일을 하나만 가져오기
const [file] = files;
// 업로드할 파일이 기존 파일과 똑같은 파일일경우 그냥 return
if (!file) {return}
// fileName 지정 (new Date.getTime으로 파일명 한글/영어 관계없도록, supabase 한글지원x)
const fileName = `${new Date().getTime()}`;
// 파일 업로드
await supabase.storage.from("avatars").upload(fileName, file);
const newProfileUrl = `${import.meta.env.VITE_SUPABASE_URL}/storage/v1/object/public/avatars/${fileName}`;
setProfileUrl(newProfileUrl);
// 유저정보에 fileName 추가&업데이트
await supabase.auth.updateUser({ data: { fileName: fileName } });
};
(5) 완성한 코드
const Avatar = () => {
const [profileUrl, setProfileUrl] = useState("");
const { userInfo } = useContext(EntireContext);
const fileInputRef = useRef(null);
useEffect(() => {
checkProfile();
}, []);
const checkProfile = async () => {
// userInfo.user_metadata에 fileName 이 존재하면 setProfileUrl에 publicUrl 값을 업데이트
if (userInfo.user_metadata.fileName) {
const {
data: { publicUrl }
} = await supabase.storage.from("avatars").getPublicUrl(userInfo.user_metadata.fileName);
setProfileUrl(publicUrl);
} else { // 아닌 경우 default-profile 이미지를 가져와서 그 링크를 넣어줌
const {
data: { publicUrl }
} = await supabase.storage.from("avatars").getPublicUrl("default-profile.jpg");
setProfileUrl(publicUrl);
}
};
const handleFileInputChange = async (e) => {
const files = e.target.files;
const [file] = files;
if (!file) {
return;
}
const fileName = `${new Date().getTime()}`;
const { data, error } = await supabase.storage.from("avatars").upload(fileName, file);
console.log(data);
console.log(error);
const newProfileUrl = `${import.meta.env.VITE_SUPABASE_URL}/storage/v1/object/public/avatars/${fileName}`;
setProfileUrl(newProfileUrl);
const { error: updateError } = await supabase.auth.updateUser({
data: { fileName: fileName }
});
};
return (
<>
<input onChange={handleFileInputChange} type="file" ref={fileInputRef} hidden />
<ProfileImg width={45} height={45} src={profileUrl} alt="profile" onClick={() => fileInputRef.current.click()} />
</>
);
};
■ 닉네임 불러오기 및 수정
(1) 닉네임 불러오기
// 닉네임 상태를 관리하는 state 생성
const [nickname, setNickname] = useState("");
// EntireContext 에서 userInfo 가져오기
const { userInfo } = useContext(EntireContext);
useEffect(() => {
checkNickname();
}, []);
// userInfo.user_metadata 에 존재하는 nickname 값을 setNickname에 넣어줌
const checkNickname = async () => {
setNickname(userInfo.user_metadata.nickname);
};
(2) 닉네임 업데이트
// 변경할 닉네임을 관리할 state 생성
const [updateNickname, setUpdateNickname] = useState("");
// 변경할 닉네임 값을 받을 input 창에 연결할 onChange 함수
const handleNicknameChange = (e) => {
setUpdateNickname(e.target.value);
};
// 닉네임 업데이트 함수
const handleNicknameUpdate = async () => {
// updateUser 메서드로 nickname을 입력받을 updateNickname로 업데이트
const { data } = await supabase.auth.updateUser({
data: { nickname: updateNickname }
});
// 업데이트한 닉네임을 setNickname 해주기
setNickname(data.user.user_metadata.nickname);
// Input창 초기화
setUpdateNickname("");
};
(3) 수정 버튼 클릭 시 닉네임 p 태그를 input 창으로 바꿔주면서 버튼도 다르게 보여주기
// 초기값이 false 인 edited state 생성
const [edited, setEdited] = useState(false);
const handleNicknameUpdate = async () => {
const { data } = await supabase.auth.updateUser({
data: { nickname: updateNickname }
});
setNickname(data.user.user_metadata.nickname);
setUpdateNickname("");
setEdited(false);
};
const handleNicknameEdit = () => {
setEdited(true);
};
return (
<NicknameContainer>
{edited ? (
<EditInput type="text" placeholder="닉네임 입력" value={updateNickname} onChange={handleNicknameChange} />
) : (
<NicknameText>{nickname}</NicknameText>
)}
{edited ? (
<EditBtn type="button" onClick={handleNicknameUpdate}>
✔
</EditBtn>
) : (
<EditBtn type="button" onClick={handleNicknameEdit}>
✐
</EditBtn>
)}
</NicknameContainer>
);
(4) 완성 모습
■ 발생한 오류
이미지를 업로드 할 때 파일명이 한글일 경우 이미지 업로드가 안되고 이미지가 깨지는 오류가 발생했다.
■ 해결방법
supabase 에서 한글을 지원하지 않아서 생기는 오류로 확인되었다.
파일명이 브라우저 내에서 쓰이고 있지 않아서 필요하진 않는 부분이라 file.name 을 new Date().getTime()으로 변경해서 해결하였다.
// 기존 코드의 파일명
const fileName = `${file.name}-${Math.random()}`;
// 변경한 파일명
const fileName = `${new Date().getTime()}`;
■ 느낀점
일단 supabase 활용하는 것 부터 익숙하지 않았고 superbase에서 제공하는 docs api를 어떻게 활용해야하는지 감도 안와서 많이 막혔었다. 이런 로직을 이해하려고 하기보단 사용방법대로 그냥 쓰면 된다고 여러번 들었던 말이지만 그래도 여전히 어려웠다.
그래서 제일 먼저 시작했던 프로필 부분에서 시간이 엄청 많이 걸렸는데 그 이후 닉네임부터는 좀 수월했다. 두가지 기능을 구현하고 나니 api 사용방법들에 조금 감이 생겼다. 이제 유저가 작성한 게시물 불러오기, 시간이 된다면 비밀번호 수정 기능까지도 해봐야겠다.
'TIL' 카테고리의 다른 글
뉴스피드 팀 프로젝트 ④ - 기능구현(비밀번호 변경) (3) | 2024.09.03 |
---|---|
뉴스피드 팀 프로젝트 ③ - 기능구현(내가 작성한 게시물) (0) | 2024.09.02 |
뉴스피드 팀 프로젝트 ① - 기획 (7) | 2024.08.28 |
개인과제 - 포켓몬도감 만들기 ④ (0) | 2024.08.27 |
개인과제 - 포켓몬도감 만들기 ③ (0) | 2024.08.26 |