yamoo9 / likelion-FEQA

질문/답변 — 프론트엔드 스쿨, 멋사
29 stars 9 forks source link

[LAB-8] 유저 컬렉션 생성이 안 됩니다! #225

Closed rlawlsdn263 closed 1 year ago

rlawlsdn263 commented 1 year ago

질문 작성자

김진우

문제 상황

async function registerUser() {
    try {
      const user = await createUserWithEmailAndPassword(
        auth,
        email,
        password,
      )
      console.log("회원가입 성공!");
    } catch(error) {
      console.log(error.message);
    }
  }

createUserWithEmailAndPassword()으로 회원가입 기능을 만들었습니다. 하지만 보다 다양한 유저 정보를 심어주고 싶어 회원가입이 되면 input값으로 들어간 데이터들이 심어진 유저 컬렉션을 만들려고 했습니다.

async function addUserCollection(name, mobile, email) {
    await setDoc(doc(db, "users", "a"), {
      name: name,
      mobile: mobile,
      email: email,
    })
  }
function handleCheckRegister() {
    if(email === "" || emailVisible === true) {
      console.log('응 이메일 탈락~');
      return;
    } else if (password === "" || passwordVisible === true) {
      console.log('응 비번 탈락~');
      return;
    } else if (passwordConfirm === "" || passwordConfirmVisible === true) {
      console.log('응 비번중복 탈락~');
      return;
    } else if (name === "" || nameVisible === true) {
      console.log('응 이름 탈락~');
      return;
    } else if (mobile === "" || mobileVisible === true) {
      console.log('응 휴대폰 탈락~');
      return;
    } else if (checkedTerms === false) {
      console.log('이용약관 체크 안함');
      return;
    } else if (checkedAge === false) {
      console.log('나이 확인 안함');
      return;
    } else {
      console.log('이야 이걸 통과하네ㅋ');
      registerUser();
      addUserCollection(name, mobile, email);
    }
  }

그래서 addUserCollection() 함수를 만들고 다음 조건에 적합하면 순차적으로 실행을 해주려고 했습니다.

image

하지만 다음처럼 에러가 발생해 생성이 되지 않고 있는 상황입니다ㅠ

프로젝트 저장소 URL

https://github.com/likelion-frontendo/likelion-saja/blob/feature%2Fjinwoo%2Fregister/src/pages/Register/Register.jsx

yamoo9 commented 1 year ago

문제 원인

useCurrentUser 훅이 함수 컴포넌트 내부에 작성되어 있었습니다.

문제 해결

useCurrentUser 훅을 컴폰넌트 외부로 분리하고 아래와 같이 작성합니다.

function useCurrentUser() {
  const [currentUser, setCurrentUser] = useRecoilState(currentUserAtom);

  useEffect(() => {
    onAuthStateChanged(auth, (user) => {
      if (user) {
        const currentUser = {uid: user.uid, email: user.email};
        console.log(currentUser);
        setCurrentUser(currentUser);
      }
    });
  }, [setCurrentUser]);

  return currentUser;
}

그리고 컴포넌트 코드는 아래처럼 작성합니다.

function Register() {
  // ...
  const userObject = useCurrentUser();

  async function handleCheckRegister() {
    if (email === "" || emailVisible === true) {
      console.log("응 이메일 탈락~");
      return;
    } else if (password === "" || passwordVisible === true) {
      //...
    } else {
      console.log("이야 이걸 통과하네ㅋ");
      await registerUser();
      await addUserCollection(name, mobile, email);
    }
  }

  // /* 파이어베이스 회원가입 기능 */
  async function registerUser() {
    try {
      const user = await createUserWithEmailAndPassword(auth, email, password);
      console.log("회원가입 성공!", user);
    } catch (error) {
      console.log(error.message);
    }
  }

  async function addUserCollection(name, mobile, email) {
    await setDoc(doc(db, "users", "a"), {
      name: name,
      mobile: mobile,
      email: email,
    });
    console.log("사용자 정보 추가");
  }

  return (<> ... </>);
}

그러면 아래처럼 정상적으로 작동합니다. 😊 Firestore 데이터베이스에 사용자 정보가 저장되는 지는 직접 확인 바랍니다. (저는 볼 수 없어요 😅)

가이드 파일

첨부된 가이드 파일을 다운로드 받아 확인해보세요.

src.zip

rlawlsdn263 commented 1 year ago

야무쌤 감사합니다! 성공적으로 유저 컬렉션이 만들어지는 걸 확인했습니다. 추가 질문이 있는데

function useCurrentUser() {
    const [currentUser, setCurrentUser] = useRecoilState(currentUserAtom);

    useEffect(() => {
      onAuthStateChanged(auth, (user) => {
        if(user) {
          const currentUser = {uid: user.uid, email: user.email};
          console.log(currentUser);
          setCurrentUser(currentUser);
        }
      });
    }, [setCurrentUser]);

    return currentUser;
  }

useCurrentUser()을 내부에서 setCurrentUser()가 실행되면 currentUser 상태변수가 업데이트 하게끔 해줬습니다. 그렇다면 currentUser 상태변수에는 새로 업데이트된 값이 들어가 있어야 할 텐데 콘솔창으로 확인을 해보니 onAuthStateChanged()가 실행됐음에도 currentUser 상태변수는 여전히 비어있었습니다.

image

image

리액트에서 currentUser 값을 비동기적으로 업데이트해줘서 그런 걸까요?

yamoo9 commented 1 year ago

@rlawlsdn263 님

리액트 상태 업데이트는 즉시 이뤄지지 않습니다. 🤔 이번 프로젝트 진행하면서 자주 받는 질문이다 보니 별도로 "상태 업데이트" 레이블을 추가했어요.

🆀 상태 업데이트 관련 질문/답변 보기

useCurrentUser 훅이 반환하는 currentUser 상태 값이 업데이트 된 이후, 콜백(실행) 하려면? useEffect 훅을 사용해주세요. 그래야 상태가 업데이트 됨을 보장할 수 있습니다.

const currentUser = useCurrentUser();

useEffect(() => {
  console.log("useEffect 내부:", currentUser);
}, [currentUser]);

아래 Console 패널에 출력된 currentUser 값을 보면 상태가 업데이트 되면 콜백 됨을 확인할 수 있습니다. 😃

일반적인 사고로는 회원 가입하면 currentUser 상태가 업데이트 되었을 것 같지만, 리액트처럼 사고 해야 왜 상태가 바로 업데이트 되지 않는 지 이해할 수 있어요. 🥹 (Thinking in React)