ログイン時にユーザーコレクションからユーザーデータを取得する

Nov 21 2020

現在、クライアント側でFirebaseが初期化されたアプリケーションに取り組んでいます。ユーザーがFirebase経由でログインするときに、Firestoreからユーザーのデータを取得したいと思います。私は現在、onAuthStateChangedリスナー内でこれを行っており、ユーザーを正常にフェッチしています。これがユーザーデータを取得するための最良の方法であるかどうか疑問に思っています。私のコードは次のとおりです。

  const [currentUser, setCurrentUser] = useState(null)
  const [authState, setAuthState] = useState(false)

  useEffect(() => {
    console.log('state unknown')
    setAuthState(false)
    auth().onAuthStateChanged(user => {
      if (!user) {
        return
      }
      const sourceRef = firestore()
        .collection('users')
        .where('userId', '==', user.uid)
      sourceRef
        .get()
        .then(snapshot => {
          if (snapshot.empty) {
            console.log('user not found')
          } else {
            let data = {}
            snapshot.forEach(item => (data = item.data()))
            console.log(data)
            setCurrentUser(data)
            setAuthState(true)
          }
        })
        .catch(error => console.log(error.code))
    })
  }, [])

  return (
    <AppContext.Provider value={{ currentUser, authState }}>
      {children}
    </AppContext.Provider>
  )
}

私の主な関心事は、アプリケーションが更新されるたびにユーザーのデータがフェッチされることです。この問題に関する提案やベストプラクティスをいただければ幸いです。

回答

2 LouisCoulet Nov 21 2020 at 17:55

コンテキストAPIと認証オブザーバーを使用したアプローチはすでに優れていますが、小さな問題があります。

  • Awran5が述べているように、オブザーバーの登録を解除する必要があります
  • ユーザーデータを1回だけフェッチする代わりに、監視することができます
  • 読みやすさとパフォーマンスのためにコンテキストを分離できます
  • 所有者のIDを使用してコレクションユーザーにドキュメントを作成できるためcollection("users").doc(authUser.uid)、クエリを実行する代わりに直接アクセスできます

これが私があなたの例をどのように修正するかです、それが最良の方法であるかどうかはわかりません、私は他の人のコメントを待っています:

const AuthContext = React.createContext();

function AuthProvider({ children }) {
    const [authUser, setAuthUser] = React.useState(undefined);

    React.useEffect(() => {
        return firebase.auth().onAuthStateChanged(user => setAuthUser(user));
    }, []);

    return <AuthContext.Provider value={authUser}>{children}</AuthContext.Provider>;
}
const UserDataContext = React.createContext();

function UserDataProvider({ children }) {
    const [userData, setUserData] = React.useState(null);
    const authUser = React.useContext(AuthContext);

    React.useEffect(() => {
        if (!authUser) return;
        const query = firebase.firestore().collection("/users").where("userId", "==", authUser.uid);
        return query.onSnapshot(snapshot => setUserData(snapshot.empty ? null : snapshot.docs[0].data()));
    }, [authUser]);

    return <UserDataContext.Provider value={userData}>{children}</UserDataContext.Provider>;
}
export default function App() {
    return (
        <AuthProvider>
            <UserDataProvider>
                {/* ... other components */}
                <MyComponent />
            </UserDataProvider>
        </AuthProvider>
    );
}
function MyComponent() {
    const authUser = React.useContext(AuthContext);
    const userData = React.useContext(UserDataContext);
    if (authUser === undefined) return <div>loading user authentication...</div>;
    if (authUser === null) return <div>logged out</div>;
    return <div>User data: {JSON.stringify(userData)}</div>;
}

コンポーネントは、認証状態の変更時またはユーザーデータの変更時に引き続き再レンダリングされますが、必要な場合に限ります。