Récupération des données utilisateur de la collection d'utilisateurs lors de la connexion

Nov 21 2020

Je travaille actuellement sur une application avec firebase initialisé côté client. Lorsqu'un utilisateur se connecte via Firebase, je souhaite récupérer les données de l'utilisateur depuis le firestore. Je le fais actuellement dans l' onAuthStateChangedauditeur et je récupère avec succès l'utilisateur. Je me demande si c'est la meilleure façon de récupérer les données utilisateur. Mon code est le suivant:

  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>
  )
}

ma principale préoccupation est que les données de l'utilisateur seront récupérées chaque fois que l'application est actualisée. Toutes suggestions ou meilleures pratiques en la matière seraient grandement appréciées

Réponses

2 LouisCoulet Nov 21 2020 at 17:55

À mon humble avis, votre approche utilisant l'API contextuelle et l'observateur d'authentification est déjà bonne, avec seulement des problèmes mineurs:

  • vous devez désinscrire vos observateurs comme mentionné par Awran5
  • vous pouvez observer les données utilisateur au lieu de les récupérer une seule fois
  • vous pouvez séparer vos contextes pour plus de lisibilité et de performance
  • vous pouvez créer vos documents dans les utilisateurs de la collection avec l'identifiant du propriétaire, vous pouvez donc accéder directement au collection("users").doc(authUser.uid)lieu de faire une requête

Voici comment je modifierais votre exemple, je ne sais pas si c'est le meilleur moyen, j'attends les autres commentaires:

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>;
}

Vos composants seront toujours rendus lors du changement d'état d'authentification ou de la modification des données utilisateur, mais uniquement si nécessaire.