TIL_230216

그래도 해야지·2023년 2월 16일
0

TIL

목록 보기
36/44

📝 To Do List


☠️ 문제 1

어제 있었던 이미지 수정은 잘 되는데 새로고침을 하면 리프레시 되는 이슈는 고쳤다.

그래서 이미지 수정은 잘 되는데,

문제는 사진에 나온 것처럼 이미지만 수정을 하면 이미지 수정은 잘 되지만, 이미지 수정없이 닉네임만 수정하면 닉네임 수정이 안 됨

👩🏻‍🎓 해결

// 닉네임 바꿔주는 함수
  const submitHandle = async (e: any) => {
    console.log('currentUser', currentUser);
    e.preventDefault();
    console.log('imgFile', imgFile);
    // imgFile의 길이가 0이 아니라면
    if (imgFile.length !== 0) {
      // Firebase storage에 이미지 업로드
      const imgRef = ref(storage, `profileUploadImg/${fileName + uuidv4()}`);

      const response = await uploadString(imgRef, imgFile, 'data_url');
      const downloadImageUrl = await getDownloadURL(response.ref);
      setImgUploadUrl(downloadImageUrl);
      console.log('downloadImageUrl', downloadImageUrl);
// 프로필 업데이트를 해주는데 
// displayName은 nickname으로 
// photoURL은 downloadImageUrl로 프로필 업데이트를 해달라.
      await updateProfile(currentUser, {
        displayName: nickname,
        photoURL: downloadImageUrl,
      })
        .then(() => {
          alert('Profile updated!');
          setNickname('');
          console.log('imgUploadUrl', imgUploadUrl);

          // setImgUploadUrl('');
        })
        .catch((error) => {});
        
  // imgFile의 길이가 0이라면 displayName을 nickname으로만 바꿔줘     
    } else {
      await updateProfile(currentUser, {
        displayName: nickname,
      })
        .then(() => {
          alert('Profile updated!');
          setNickname('');
          console.log('imgUploadUrl', imgUploadUrl);

          // setImgUploadUrl('');
        })
        .catch((error) => {});
    }
  };

✅ 알게된 점

첫 렌더링이 됐을 때 user의 닉네임이 undefined되는 이유?!

  • 렌더링되는 속도가 데이터를 불러오는 속도보다 빨라서 undefined ❗

📚 Today Study

1. 이미지 수정도 되고, 닉네임만 수정해도 잘 되는 코드

import { onAuthStateChanged } from 'firebase/auth';
import { useEffect, useState } from 'react';
import { auth } from '../../services/firebase';
import {
  MyProfileWrapper,
  MyProfileNickname,
  NicknameModifyBox,
  ModifyButton,
  NicknameInput,
  ProfileImgLabel,
  ProfileImgInput,
  NewImageForm,
} from './style';
import { updateProfile } from 'firebase/auth';
import { storage } from '../../../src/services/firebase';
import { getDownloadURL, ref, uploadString } from 'firebase/storage';
import { v4 as uuidv4 } from 'uuid';

const MyProfile = () => {
  const [nickname, setNickname] = useState<any>('');
  const [currentUser, setCurrentUser] = useState<any>('');

  const [imgFile, setImgFile] = useState(''); // 이미지 파일
  const [fileName, setFileName] = useState(''); // 이미지 파일 이름.확장자
  const [imgUploadUrl, setImgUploadUrl] = useState<any>(
    auth.currentUser?.photoURL,
  );
  console.log('================================');
  console.log('imgUploadUrl ', imgUploadUrl);

  // 이미지 파일 input onChange 함수
  const newProfileImgOnChangeHandler = (
    // event : currentTarget과 target이 들어있는 객체
    event: React.ChangeEvent<HTMLInputElement>,
  ) => {
    const target = event.currentTarget;
    const theFile = (target.files as FileList)[0]; // 이벤트로부터 파일을 얻어와서 첫번째 파일만 받음
    console.log('theFile', theFile);

    setFileName(theFile.name);

    const reader = new FileReader();
    reader.readAsDataURL(theFile); // file객체를 data url로 바꿔줌

    // 파일 읽기를 끝내면 state로 만들어둔 setImgFile에 값을 넣어줌
    reader.onloadend = (finishedEvent: any) => {
      console.log('finishedEvent', finishedEvent);
      setImgFile(finishedEvent.currentTarget.result);
    };
  };

  useEffect(() => {
    auth.onAuthStateChanged((user) => {
      if (user) {
        console.log('user', user);
        // updateProfile(user )
        setCurrentUser(auth.currentUser);
        setImgUploadUrl(user.photoURL);
        // setNickname(auth.currentUser?.displayName);
        // setImgFile(user?.photoURL);
      } else {
        return console.log('로그인 안됨');
      }
    });
  }, [currentUser]);

  useEffect(() => {}, [imgUploadUrl]);

  // 닉네임 바꿔주는 함수
  const submitHandle = async (e: any) => {
    console.log('currentUser', currentUser);
    e.preventDefault();
    console.log('imgFile', imgFile);
    if (imgFile.length !== 0) {
      // Firebase storage에 이미지 업로드
      const imgRef = ref(storage, `profileUploadImg/${fileName + uuidv4()}`);

      const response = await uploadString(imgRef, imgFile, 'data_url');
      const downloadImageUrl = await getDownloadURL(response.ref);
      setImgUploadUrl(downloadImageUrl);
      console.log('downloadImageUrl', downloadImageUrl);

      await updateProfile(currentUser, {
        displayName: nickname,
        photoURL: downloadImageUrl,
      })
        .then(() => {
          alert('Profile updated!');
          setNickname('');
          console.log('imgUploadUrl', imgUploadUrl);
          // setImgUploadUrl('');
        })
        .catch((error) => {});
    } else {
      await updateProfile(currentUser, {
        displayName: nickname,
      })
        .then(() => {
          alert('Profile updated!');
          setNickname('');
          console.log('imgUploadUrl', imgUploadUrl);

          // setImgUploadUrl('');
        })
        .catch((error) => {});
    }
  };
  const NicknameChangeInput = (event: any) => {
    setNickname(event.target.value);
  };

  return (
    <NewImageForm onSubmit={submitHandle}>
      <MyProfileWrapper>
        <div>
          {/* // label태그와 input태그를 연결함으로써 label만 눌러도 프로필 업데이트가 되게 연결시킴 */}
          <ProfileImgLabel htmlFor="profileUploadImg">
            <img src={imgUploadUrl} style={{ width: 150, height: 150 }} />
          </ProfileImgLabel>
          {/* // 인풋에서 열기버튼을 누르면 파이어베이스에 올라가게 */}
          <ProfileImgInput
            type="file"
            accept="image/*"
            id="profileUploadImg"
            onChange={newProfileImgOnChangeHandler}
            style={{ display: 'none' }}
            // style={{ display: 'none' }}
          />
        </div>
        {/* <ImgModifyButton>이미지 수정완료</ImgModifyButton> */}
        <MyProfileNickname>{currentUser?.displayName}</MyProfileNickname>
        <NicknameModifyBox>
          <NicknameInput
            placeholder="닉네임을 입력해주세요"
            onChange={NicknameChangeInput}
            value={nickname}
          />

          <ModifyButton type="submit">수정</ModifyButton>
        </NicknameModifyBox>
      </MyProfileWrapper>
    </NewImageForm>
  );
};

export default MyProfile;
  1. 파이어베이스에서 프로필 닉네임을 가져오려면 getAuth를 import해야한다고 공식문서에 나와있지만 우리는 firebase.ts에 auth로 변수를 만들었기때문에 auth만 가져오면 된다.
// firebase.ts

// Initialize Firebase
import { getAuth } from 'firebase/auth';

export const auth = getAuth(app);
// MyProfile.tsx

import { auth } from '../../services/firebase';
  1. 프로필 닉네임, 이미지를 변경하려면 바꾸려는 닉네임과 이미지를 파이어베이스에 업데이트를 해줘야한다.
    그러려면 firebase공식문서에 나와있는 사용자 프로필 업데이트를 보면 됨
    updateProfile 메소드를 사용하여 사용자의 기본 프로필 정보(사용자의 표시 이름 및 프로필 사진 URL)를 업데이트할 수 있다.
    그래서 이러한 코드가 나왔다.
    여기까지도 당연히 state인 nickname, currentUser는 null이다.
import { updateProfile } from 'firebase/auth';

// updateProfile 메소드를 사용해서 currentUser의 displayName은 'Jane'으로 업데이트 해주고, photoURL은 'https://example.com/jane-q-user/profile.jpg'로 업데이트해줘

updateProfile(currentUser, {
    displayName: 'Jane',
    photoURL: 'https://example.com/jane-q-user/profile.jpg',
  })
    .then(() => {
      alert('Profile updated!');
    })
    .catch((error: any) => {
    });
  1. 닉네임 변경, 이미지 변경 다 좋다.
    하지만 이게 로그인 된 상태에서 '내' 닉네임을 변경하고, '내' 이미지를 변경해야하는 건데 그러려면 당연히 로그인이 되어있는지, 그리고 그 로그인된 게 내 계정이 맞는지 확인을 해야한다.
    그러려면 현재 로그인한 사용자를 가져와야한다.
  • auth : AuthImpl (currentUser가 UserImpl이라고 되어있음) /데이터베이스에 있는 전체 유저 정보???
  • user : UserImpl (auth도 들어있고 currentUser가 UserImpl이라고 되어있음) // 로그인

❓하지만 이 둘의 차이가 정확히 뭔지 모르겠다.
⭐⭐⭐ 나중에 이거 읽어보기
https://github.com/woob0129/VirtualTraveler/blob/master/wiki/about_firebase_auth.md


  • 현재 로그인한 사용자 가져오기
  • 파이어베이스에서 들어오는 유저가 현재 유저와 일치한다면 currentUser를 auth.currentUser를 출력해줘
  • 이전까진 currentUser가 null이였는데 useEffect내부의 함수가 실행이 되니까 리렌더링이 돼서 state로 만들었던 currentUser가 UserImpl로 변함
  useEffect(() => {
    auth.onAuthStateChanged((user) => {
      if (user) {
        setCurrentUser(auth.currentUser);
      } else {
        return console.log('로그인 안됨');
      }
    });
  }, []);
  1. 인풋창에 입력한 새로운 닉네임과 이미지를 파이어베이스에 업데이트해주는 코드
  // 닉네임, 이미지 바꿔주는 함수
  // 바꾸려는 닉네임과 이미지를 파이어베이스에 업데이트해주는 코드
  const submitNicknameImgChange = async (e: any) => {
    e.preventDefault();
    await updateProfile(currentUser, {
      displayName: nickname,
      photoURL: 'https://example.com/jane-q-user/profile.jpg',
    })
      .then(() => {
        alert('Profile updated!');
        setNickname('');
      })
      .catch((error: any) => {
        error;
      });
  };
  1. 이제 이미지 변경 시작이다!
    프로필 이미지 변경을 하기 위해선 이미지 파일을 파이어베이스에 넣어줘야하고, 파일 자체는 용량이 커서 storage에 안 올라가기 때문에 이미지파일을 url로 변경해줘야 한다.
  • 이미지 파일 자체
  • 이미지 파일 이름.확장자
  • 업로드한 이미지 url
const [imgFile, setImgFile] = useState(''); // 이미지 파일
const [imgFileName, setImgFileName] = useState(''); // 이미지 파일 이름.jpg
const [imgUploadUrl, setImgUploadUrl] = useState<any>(
    auth.currentUser?.photoURL,
); // 업로드한 이미지 url

📝 Today Review

0개의 댓글