gpt4 book ai didi

reactjs - 如何将默认 react 上下文值设置为来自 firestore 的数据?

转载 作者:行者123 更新时间:2023-12-04 03:36:11 25 4
gpt4 key购买 nike

我正在构建一个锻炼计划规划器应用程序,该锻炼程序在应用程序中使用 SetProgram 上下文进行处理,并使用名为 useProgram 的自定义 Hook 进行更新。我需要当用户登录时应用程序将从 firestore 获取数据并显示用户的锻炼计划,我该怎么做?请记住,在整个应用程序中还使用 useProgram Hook 来编辑和更新一个人的锻炼计划。

应用.tsx

import React, { useContext, useEffect, useState } from "react";
import { BrowserRouter as Router } from "react-router-dom";
import AppRouter from "./Router";
import FirebaseApp from "./firebase";

import SetProgram from "./context/program";

import { useProgram } from "./components/hooks/useProgram";
import firebaseApp from "./firebase/firebase";
import { useAuthState } from "react-firebase-hooks/auth";

function App() {
const program = useProgram();

const day = useDay();
const [user, loading, error] = useAuthState(firebaseApp.auth);


return (
<div className="App">
<SetProgram.Provider value={program}>
<Router>
<AppRouter />
</Router>
</SetProgram.Provider>
</div>
);
}

export default App;

firebase.ts

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

import firebaseConfig from "./config";


class Firebase {
auth: firebase.auth.Auth;
user: firebase.User | null | undefined;
db: firebase.firestore.Firestore;
userProgram: {} | undefined;

constructor() {
firebase.initializeApp(firebaseConfig);
this.auth = firebase.auth();
this.db = firebase.firestore();
}

async register() {
if (this.user) {
this.db.collection("users").doc(this.user.uid).set({
name: this.user.displayName,
email: this.user.email,
userId: this.user.uid,
program: {},
});
}
}

async getResults() {
return await this.auth.getRedirectResult().then((results) => {
console.log("results.user", results.user);
if (!results.additionalUserInfo?.isNewUser) {
this.getProgram();
} else {
this.register();
}
});
}

async login(
user: firebase.User | null | undefined,
loading: boolean,
error: firebase.auth.Error | undefined
) {

const provider = new firebase.auth.GoogleAuthProvider();
return await this.auth
.signInWithRedirect(provider)
.then(() => this.getResults());
}

async logout() {
return await this.auth.signOut().then(() => console.log("logged out"));
}

async updateProgram(user: firebase.User, program: {}) {
if (this.userProgram !== program) {
firebaseApp.db
.collection("users")
.doc(user.uid)
.update({
program: program,
})
.then(() => console.log("Program updated successfully!"))
.catch((error: any) => console.error("Error updating program:", error));
} else {
console.log("No changes to the program!");
}
}

async getProgram() {
firebaseApp.db
.collection("users")
.doc(this.user?.uid)
.get()
.then((doc) => {
console.log("hello");
if (doc.exists) {
this.userProgram = doc.data()?.program;
console.log("this.userProgram", this.userProgram);
} else {
console.log("doc.data()", doc.data());
}
});
}
}

const firebaseApp = new Firebase();
export default firebaseApp;

programContext.tsx

import React from "react";
import Program, { muscleGroup, DefaultProgram } from "../interfaces/program";

export interface ProgramContextInt {
program: Program | undefined;
days: Array<[string, muscleGroup]> | undefined;
setProgram: (p: Program) => void;
}

export const DefaultProgramContext: ProgramContextInt = {
program: undefined,
days: undefined,
setProgram: (p: Program): void => {},
};

const ProgramContext = React.createContext<ProgramContextInt>(
DefaultProgramContext
);

export default ProgramContext;

使用程序.tsx


import React from "react";
import {
ProgramContextInt,
DefaultProgramContext,
} from "../../context/program";
import Program, { muscleGroup } from "../../interfaces/program";
import { useAuthState } from "react-firebase-hooks/auth";
import firebaseApp from "../../firebase";

export const useProgram = (): ProgramContextInt => {
const [user] = useAuthState(firebaseApp.auth);

const [program, setEditedProgram] = React.useState<Program | undefined>();
const [days, setProgramDays] = React.useState<
[string, muscleGroup][] | undefined
>(program && Object.entries(program));

const setProgram = React.useCallback(
(program: Program): void => {
firebaseApp.updateProgram(user, program);
setEditedProgram(program);
setProgramDays(Object.entries(program));
},
[user]
);

return {
program,
days,
setProgram,
};
};

最佳答案

我认为有两种处理方式:

  1. 更新 ProgramContext 以确保用户已登录
  2. App 或您需要确保用户已登录的任何其他入口点包装在单独的 UserContextProvider

让我们谈谈后一种方法,我们可以在其中包装一个名为 UserContext 的单独上下文。 Firebase 为我们提供了一个名为 onAuthStateChanged 的监听器,我们可以在上下文中使用它,如下所示:

import { createContext, useEffect, useState } from "react";
import fb from "services/firebase"; // you need to define this yourself. It's just getting the firebase instance. that's all
import fbHelper from "services/firebase/helpers"; // update path based on your project organization

type FirestoreDocSnapshot = firebase.default.firestore.DocumentSnapshot<firebase.default.firestore.DocumentData>;

const UserContext = createContext({ user: null, loading: true });

const UserContextProvider = ({ children }) => {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const userContext = { user, loading };

const updateUser = (snapShot: FirestoreDocSnapshot) => {
setUser({
id: snapShot.id,
...snapShot.data,
});
};

const authStateListener = async (authUser: firebase.default.User) => {
try {
if (!authUser) {
setUser(authUser);
return;
}

const fbUserRef = await fbHelper.findOrCreateFirestoreUser(authUser)

if ("error" in fbUserRef) throw new Error(fbUserRef?.error);

(fbUserRef as FirestoreUserRef).onSnapshot(updateUser)
} catch (error) {
throw error;
} finally {
setLoading(false);
}
};

useEffect(() => {
const unSubscribeAuthStateListener = fb.auth.onAuthStateChanged(authStateListener);

return () => unSubscribeAuthStateListener();
}, [])

return (
<UserContext.Provider value={userContext}>
{children}
</UserContext.Provider>
)
};

export default UserContextProvider;

帮助者可以是这样的:

export type FirestoreUserRef = firebase.default.firestore.DocumentReference<firebase.default.firestore.DocumentData>

const findOrCreateFirestoreUser = async (authUser: firebase.default.User, additionalData = {}): Promise<FirestoreUserRef | { error?: string }> => {
try {
if (!authUser) return { error: 'authUser is missing!' };

const user = fb.firestore.doc(`users/${authUser.uid}`); // update this logic according to your schema
const snapShot = await user.get();

if (snapShot.exists) return user;

const { email } = authUser;

await user.set({
email,
...additionalData
});

return user;
} catch (error) {
throw error;
}
};

然后将提供 firestore 数据的其他上下文包装在此 UserContextProvider 中。因此,无论何时您登录或注销,都会调用这个特定的监听器。

关于reactjs - 如何将默认 react 上下文值设置为来自 firestore 的数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66864342/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com