Pobieranie danych użytkownika z kolekcji użytkownika przy logowaniu
Obecnie pracuję nad aplikacją z uruchomionym firebase po stronie klienta. Gdy użytkownik loguje się przez Firebase, chcę pobrać dane użytkownika z Firestore. Obecnie robię to w onAuthStateChanged
odbiorniku i pomyślnie pobieram użytkownika. Zastanawiam się, czy to najlepszy sposób na pobranie danych użytkownika. Mój kod wygląda następująco:
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>
)
}
moim głównym zmartwieniem jest to, że dane użytkownika będą pobierane za każdym razem, gdy aplikacja zostanie odświeżona. Wszelkie sugestie lub najlepsze praktyki w tej sprawie będą bardzo mile widziane
Odpowiedzi
IMHO Twoje podejście przy użyciu kontekstowego API i obserwatora uwierzytelniania jest już dobre, z niewielkimi problemami:
- powinieneś wypisać się ze swoich obserwatorów, jak wspomniał Awran5
- można było obserwować dane użytkownika zamiast pobierać je tylko raz
- możesz oddzielić swoje konteksty dla czytelności i wydajności
- możesz tworzyć swoje dokumenty w kolekcji użytkowników z identyfikatorem właściciela, dzięki czemu możesz uzyskać bezpośredni dostęp
collection("users").doc(authUser.uid)
zamiast wykonywania zapytania
Oto jak zmodyfikowałbym Twój przykład, nie jestem pewien, czy to najlepszy sposób, czekam na komentarze innych:
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>;
}
Twoje komponenty będą nadal renderowane ponownie po zmianie stanu autoryzacji lub zmianie danych użytkownika, ale tylko w razie potrzeby.