Today I Learned
- firebase에 저장된 프로필 정보 가져오기
- 닉네임 변경 시 새로고침 없이 변경된 닉네임 보여주기
- 프로필 변경 javascript 함수 분리
- 닉네임 수정 버튼에 토글 기능 구현
해결하는 경험
firebase에서 user email 정보 가져오기
마이페이지에 가입할 때 firebase에 저장된 이메일 주소를 불러오고 싶었다. 프로필 이미지와 닉네임을 불러올 때 사용했던 코드를 그대로 사용하면 될 거 같아서 일단 console.log로 이메일 정보가 어디에 저장되어 있는지 확인했다.
document.getElementById("profileEmail").textContent =
authService.currentUser.email ?? "이메일 없음";
email이 담긴 위치를 확인한 후 router.js에 위의 코드를 추가했다. (main.js도 수정함) 결과적으로 마이페이지에 내가 가입한 이메일 정보를 불러올 수 있었다.
닉네임 수정 시 변경된 닉네임으로 업데이트하는 문제
닉네임 수정 버튼을 눌렀을 때 닉네임이 변경되기는 하지만 변경된 닉네임이 자동으로 업데이트되지 않고 예전 닉네임이 그대로 화면에 남아있다. 이 상황에서 새로고침을 해야만 변경된 닉네임가 출력된다. 하지만 나는 닉네임 변경 버튼을 누르면 전체 새로고침을 하지 않더라도 변경된 닉네임 값이 출력되기를 원했다.
export const changeProfileNickname = async (event) => {
event.preventDefault();
const newNickname = document.getElementById("profileNickname").value;
// input 창에 입력값이 있을 때만 닉네임 변경 기능이 작동함
if (document.getElementById("profileNickname").value !== "") {
await updateProfile(authService.currentUser, {
displayName: newNickname ? newNickname : null,
})
.then(() => {
alert("닉네임 수정 완료");
// 닉네임 수정 시 수정된 닉네임으로 새로고침 없이 자동 업데이트됨
const updatedDisplayName = authService.currentUser.displayName;
document.getElementById("profileNickname_val").textContent = updatedDisplayName;
// input창 입력값 리셋하기
document.getElementById("profileNickname").value = null;
})
.catch((error) => {
alert("프로필 수정 실패");
console.log("error:", error);
});
};
};
이 문제는 changeProfileNickname 함수에 updatedDisplayName 변수를 새로 지정해서 업데이트된 닉네임을 불러오는 방법으로 해결할 수 있었다.
프로필 이미지 업로드, 닉네임 변경 함수 나누기
기존에는 이미지 변경 버튼 혹은 닉네임 수정 어떤 버튼을 누르든 두 개의 정보가 한 번에 데이터베이스에 저장되는 구조였는데 튜터님에게 DB에 한 가지씩만 저장되도록 하는 게 좋을 거 같다는 피드백을 받고 함수를 두 개로 나누는 방향으로 JS 코드를 수정했다. 확실히 이렇게 하는 것이 비효율적인 DB 저장을 막아주는 거 같다.
수정 전 changeProfile -> 수정 후 changeProfileImage, changeProfileNickname
닉네임 수정 버튼에 토글 기능 넣기
닉네임 수정 기능을 어떤 방식으로 구현할까 고민을 많이 했었다. 아예 input창을 닉네임 밑에 놓는 방법도 있고, 토글 기능으로 input 창을 보여줄 수도 있고, 모달 창을 띄우는 방법도 있었다. 결과적으로는 토글 기능을 이용하기로 했는데 과연 사용자가 닉네임 수정 버튼을 누르면 input 창이 뜬다는 것을 직관적으로 파악할 수 있을까 고민이 되기는 한다.
class에 on 값을 넣었다 빼는 방법도 공부했었는데 이번에는 다른 방법을 이용해봤다. 해당 태그 자체에서 display 속성을 block과 none으로 변경하는 방법이다. javascript ES6 module에서 주의해야 할 점은 모든 함수를 export, import한 후에 전역 함수 설정까지 해줘야 한다는 것이다.
ex) window.nicknameBtn = nicknameBtn;
export const nicknameBtn = () => {
const nameVal = document.getElementById('profileNickname_val');
const nameInput = document.getElementById('profileNickname');
if(nameVal.style.display !== 'block') {
nameVal.style.display = 'block';
nameInput.style.display = 'none';
} else {
nameVal.style.display = 'none';
nameInput.style.display = 'block';
};
};
참고했던 블로그 링크를 못 찾겠다..
닉네임 수정 토글 기능에 if문으로 조건 추가하기
닉네임 수정 버튼에 닉네임 수정 input창을 띄우는 토글 기능을 넣고 싶은데 닉네임 수정 버튼을 누를 때마다 프로필 변경 함수가 작동되어서 '프로필 수정 완료'라는 alert이 뜬다. 나는 닉네임 수정 버튼 클릭 -> input 창 토글 -> iuput창에 변경할 닉네임 입력 -> 닉네임 수정 버튼 클릭해서 닉네임 변경 이런 로직을 원했기 때문에 닉네임 수정 버튼에 토글만 연결할 수 있는 방법이 뭐가 있을까 계속 고민하다가 input창에 입력된 값이 없을 때는 닉네임이 변경되지 않도록 하면 되지 않을까?라는 생각이 들었다. 그래서 changeProfileNickname 함수 안에 if문을 넣어서 input창의 값이 있을 때만 닉네임 변경 기능을 실행하도록 했더니 드디어 마음대로 토글이 가능해졌다 대박!!!!!
export const changeProfileNickname = async (event) => {
event.preventDefault();
// .disabled로 profileBtn 한 번만 클릭할 수 있도록 함 (한 번 클릭하면 비활성화됨)
// document.getElementById("profileNicknameBtn").disabled = true;
const newNickname = document.getElementById("profileNickname").value;
if (document.getElementById("profileNickname").value !== "") {
await updateProfile(authService.currentUser, {
displayName: newNickname ? newNickname : null,
})
.then(() => {
alert("프로필 수정 완료");
const updatedDisplayName = authService.currentUser.displayName;
document.getElementById("profileNickname_val").textContent = updatedDisplayName;
})
.catch((error) => {
alert("프로필 수정 실패");
console.log("error:", error);
});
};
};
근데 작은 문제를 발견했는데 닉네임 변경 후에 닉네임 수정 버튼을 누르면 이전에 입력했던 값이 input창에 그대로 남아있어서 또 다시 버튼을 누를 때마다 alert창이 뜬다. 이 문제를 해결하기 위해서 데이터를 제출하고 나면 input창에 입력된 값이 지워지도록 하고 싶었다.
document.getElementById("profileNickname").value = null;
많은 시행착오가 있었지만 결과적으로는 위와 같은 코드를 changeProfileNickname 함수의 if문 안에 추가하는 것으로 문제를 해결했다.
토글 기능이 버튼을 두 번 클릭해야 작동하는 문제
닉네임 수정 버튼이 꼭 처음에는 두 번을 눌러야 토글 기능이 작동되어 input 창이 떴다. 어디가 문제일까 여기저기 살펴보다가 개발자 도구에서 버튼 display 값이 어떻게 변하는지 봤는데 처음에 생성되는 값이 현재 닉네임 display: block; 닉네임 입력 창이 display: none;이 된다는 것을 발견했다. 버튼을 한 번 누르면 현재와 동일한 속성 값이 주어지고, 두 번째 눌렀을 때에야 반대의 속성 값이 주어지는 것이었다.
<div id="profileNickname_val" class="profile__name-val" style="display: block;">현재 닉네임</div>
<input id="profileNickname" class="profile__name-input" type="text" placeholder="변경할 닉네임" style="display: none;" maxlength="10" value="" />
export const nicknameBtn = () => {
const nameVal = document.getElementById('profileNickname_val');
const nameInput = document.getElementById('profileNickname');
if(nameVal.style.display !== 'block') {
nameVal.style.display = 'block';
nameInput.style.display = 'none';
} else {
nameVal.style.display = 'none';
nameInput.style.display = 'block';
};
};
문제를 해결하기 위해서 원래 css에 작성했었던 diaplay 속성을 지우고 html 태그 안에 display 속성을 추가했더니 버튼을 한 번만 눌러도 토글 기능이 정상적으로 작동되는 것을 확인할 수 있었다.
느낀 점
에러 가면 에러 온다.. 진짜 끝없는 에러에 미쳐버릴 뻔했다. 그냥 모든 에러와 마이페이지 화면 보는 거 자체가 너무 지겨웠음ㅠㅠ 그래도 끝까지 포기하지 않으니 일단 내가 원하는 기능들은 모두 구현에 성공했다. 근데 지금까지는 내가 임시로 제작한 SPA에서 작동한 것이었고 이제 우리 팀의 SPA와 합치는 과정이 남았다. (그리고 디자인적인 추가 수정과 하단에 내가 작성한 글까지) merge는 경험해 본 적이 없어서 브랜치를 merge하는 과정에서 어떤 충돌이 날 것인지 두렵다.🤯 내가 main.js랑 router.js도 여기저기 수정한 곳이 많아서 이게 잘 합쳐지려나 모르겠네..