React:将 Firestore 信息传递给组件的最佳方式?

时间:2021-05-24 23:06:19

标签: reactjs firebase google-cloud-firestore

无法找到一种有效的方法来设置用户的个人资料,然后根据需要将该数据继续传递给其他组件。

以下是我当前逻辑的示例,虽然该应用程序有效,但渲染效率不高。当我点击应用的各个部分时,来自我的 UserProfile 组件的数据每次都会重新呈现,导致文本从初始文本更改为呈现的数据文本。

主要问题,我认为是下面的UserProfile仪表板主页 片段之间的通信。我是 useEffect 逻辑的新手,所以我认为低效的设置是使用该钩子。

感谢任何帮助或推动正确方向!

谢谢

AuthContext 文件 => 设置当前用户

import React, { useContext, useState, useEffect } from 'react';
import firebase from 'firebase/app';
import {
    auth,
    signInWithGoogle,
    createUserProfileDocument,
    firestore,
} from '../firebase.utils';

const AuthContext = React.createContext();

export const useAuth = () => {
    return useContext(AuthContext);
};

export const AuthProvider = ({ children }) => {
    const [currentUser, setCurrentUser] = useState();
    const [loading, setLoading] = useState(true);

    const signup = (email, password) => {
        return auth.createUserWithEmailAndPassword(email, password);
    };

    const login = (email, password) => {
        return auth.signInWithEmailAndPassword(email, password);
    };

    const logout = () => {
        setCurrentUser(null);
        return auth.signOut();
    };

    const resetPassword = email => {
        return auth.sendPasswordResetEmail(email);
    };

    const updateEmail = email => {
        return currentUser.updateEmail(email);
    };

    const updatePassword = password => {
        return currentUser.updatePassword(password);
    };

    const deleteProfile = () => {
        currentUser.delete();
        firestore.doc(`users/${currentUser.uid}`).delete();
    };

    const updateName = displayName => {
        return currentUser.updateProfile({
            displayName: displayName,
        });
    };

    const setName = displayName => {
        return auth.currentUser.updateProfile({
            displayName: displayName,
        });
    };

    const googleSignIn = () => {
        const google = signInWithGoogle();
        setCurrentUser(google);
        return google;
    };

    const updatePersonalSettings = data => {
        createUserProfileDocument(currentUser, data);
    };

    const updateAccountSettings = data => {
        createUserProfileDocument(currentUser, data);
    };

    console.log(currentUser);

    useEffect(() => {
        const unsubscribe = auth.onAuthStateChanged(user => {
            setCurrentUser(user);
            setLoading(false);
        });
        return unsubscribe;
    }, []);

    const value = {
        currentUser,
        login,
        signup,
        logout,
        resetPassword,
        updateEmail,
        updatePassword,
        updateName,
        setName,
        googleSignIn,
        updatePersonalSettings,
        updateAccountSettings,
        deleteProfile,
    };

    return (
        <AuthContext.Provider value={value}>
            {!loading && children}
        </AuthContext.Provider>
    );
};

UserProfile 文件 => 设置用户信息

import { useState, useEffect } from 'react';
import { useAuth } from '../context/auth-context';
import { createUserProfileDocument } from '../firebase.utils';

const UserProfile = () => {
    const { currentUser } = useAuth();
    const [userInfo, setUserInfo] = useState();
    const [loading, setLoading] = useState(true);

    const setUserData = async () => {
        if (currentUser) {
            const userRef = await createUserProfileDocument(currentUser);
            userRef.onSnapshot(doc => {
                setUserInfo({
                    id: doc.id,
                    ...doc.data(),
                });
            });
        }
    };

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

    return { userInfo };
};

export default UserProfile;

仪表板主页文件 => 来自 UserProfile 组件的渲染数据示例

import React, { useState } from 'react';
import { Link } from 'react-router-dom';
import sprite from '../../../../assets/sprite.svg';
import UserProfile from '../../../../user-profile/user-profile';
import './home-dashboard.styles.scss';

const HomeDashboard = () => {
    const { userInfo } = UserProfile();

    const handleCurrentLevel = () => {
        return !userInfo || userInfo.currentLevel === undefined ? (
            <h1>Welcome! Start your eval to see your level</h1>
        ) : (
            <h1>Current Level: {userInfo.currentLevel}</h1>
        );
    };

    const handleCurrentLevelCard = () => {
        return !userInfo || userInfo.currentLevel === undefined
            ? 'Start a new eval to see your level'
            : `You scored a ${userInfo.currentLevel} in your last eval`;
    };

    return (
        <div className="home-dash">
            <div className="home-dash__title">{handleCurrentLevel()}</div>
            <div className="home-dash__cards">
                <div className="home-dash__card-1">
                    <svg className="icon home-dash__card-icon">
                        <use href={sprite + '#card-icon-success'}></use>
                    </svg>

                    <h3 className="home-dash__card-title">
                        Latest Eval Results
                    </h3>
                    <div className="home-dash__card-result-text">
                        {handleCurrentLevelCard()}
                    </div>
                    <Link to="/eval-quiz">
                        <button className="home-dash__card-btn--purple">
                            Start New Eval
                        </button>
                    </Link>
                </div>
                {/* TODO Add resutls to firestore */}
                {
                    <div className="home-dash__card-2">
                        <svg className="icon home-dash__card-icon">
                            <use href={sprite + '#card-icon-lightbulb'}></use>
                        </svg>

                        <h3 className="home-dash__card-title">
                            Areas to practice
                        </h3>
                        <div className="home-dash__card-result-text">
                            We recommend working on reading skills
                        </div>
                        {/*<button className="home-dash__card-btn--blue">
                            Practice
                </button>*/}
                        <div className="home-dash__coming-soon">
                            Coming soon!
                        </div>
                    </div>
                }
            </div>
        </div>
    );
};

export default HomeDashboard;

Firestore/Firebase 设置

import firebase from 'firebase/app';
import 'firebase/firestore';
import 'firebase/auth';

const app = firebase.initializeApp({
    apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
    authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
    projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
    storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
    messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER,
    appId: process.env.REACT_APP_FIREBASE_APP_ID,
    measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID,
});

export const createUserProfileDocument = async (userAuth, additionalData) => {
    if (!userAuth) return;

    const userRef = firestore.doc(`users/${userAuth.uid}`);
    const snapShot = await userRef.get();

    const { displayName, email, photoURL } = userAuth;
    const createdAt = new Date();

    if (!snapShot.exists) {
        console.log(displayName);
        try {
            await userRef.set({
                displayName,
                photoURL,
                email,
                createdAt,
                ...additionalData,
            });
        } catch (error) {
            console.log('error catching data', error.message);
        }
    }

    if (snapShot.exists) {
        try {
            await userRef.update({
                displayName,
                email,
                ...additionalData,
            });
        } catch (error) {
            console.log('error catching data', error.message);
        }
    }

    return userRef;
};

export const firestore = firebase.firestore();

const googleProvider = new firebase.auth.GoogleAuthProvider();
googleProvider.setCustomParameters({ prompt: 'select_account' });
export const signInWithGoogle = () => auth.signInWithPopup(googleProvider);

export const auth = app.auth();

export default app;

1 个答案:

答案 0 :(得分:0)

将此答案视为草稿,我已将其公之于众,以防您将其拼凑在一起,但我会在早上用一些文档对其进行更新。

import { useState, useEffect } from 'react';
import { useAuth } from '../context/auth-context';
import { createUserProfileDocument } from '../firebase.utils';

const UserProfile = () => {
    const { currentUser } = useAuth();
    const [userInfo, setUserInfo] = useState();
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        if (!currentUser) {
            // user is signed out
            setUserInfo(null);
            setLoading(false);
            return;
        }

        const userRef = /* ... */;
        setUserInfo(undefined); // clear stale data
        setLoading(true); // update loading status

        return userRef.onSnapshot({
            next(snapshot) {
                if (!snapshot.exists) {
                    userRef
                        .set({
                            /* new data */
                        })
                        .catch((err) => {
                            // TODO: Handle errors
                        });
                    return;
                }

                setUserInfo({
                    id: snapshot.id,
                    ...snapshot.data(),
                });
                setLoading(false);
            },
            error(err) {
                // TODO: Handle errors
            }
        });
    }, [currentUser]);

    return { userInfo }; // <-- this seems odd? missing loading?
};

export default UserProfile;