使用Cloud Firestore和Reactjs的最佳做法

6l7fqoea  于 2023-03-17  发布在  React
关注(0)|答案(2)|浏览(103)

更具体地说,我想了解状态管理和阅读firestore的最佳实践,在开始为我正在工作的网站设置和布局数据模型后,我开始对此感到疑惑。我目前对firestore的理解是,从集合或文档获取数据的最基本方法是使用get()方法来接收一次读取,或者使用onSnapshot()来接收文档的实时数据流。由于这些不同的方法,我开始思考设置组件和状态逻辑的最佳方法。
1.最初可以调用get()方法并将其设置为组件状态。然后,您可以使用该状态将数据传递给组件和子组件。要写入/和删除数据,您可以同时写入/删除状态和Firestore文档。这似乎具有读取受限的优点,但是更多的写入。这似乎也增加了组件状态和实际文档之间去同步的可能性。
1.为了减少写入量,是否可以继续写入/删除状态,而不是同时写入/删除firestore文档?相反,您是否可以使用useEffect返回函数在组件卸载后写入/删除状态和文档之间的差异?此选项似乎具有有限的读取和写入,并且具有单一的数据真实来源(状态)。但是,卸载文档写入的逻辑可能更加复杂。
1.似乎还可以使用onSnapshot()方法来移除状态上的并发写入/移除,并且只在文档上使用它们。似乎可以监听文档的更改,并且每次都可以直接从该文档更新状态。此选项似乎具有简单的状态逻辑和状态与文档之间不同步的优点。但反过来,这似乎会导致大量的读取和写入。
我还没有找到太多直接讨论这些想法的信息,我很好奇在处理与上述示例相关的数据流和状态管理方面,当前的最佳实践是什么。

slwdgvem

slwdgvem1#

为应用程序创建上下文

首先,我们将为firestore访问创建一个上下文,并将应用程序与其提供程序(我们称之为AuthProvider) Package 在一起,我们将创建一个挂钩useAuth来访问必要的方法或访问firestore-db
让我们从创造一个环境开始-

import { initializeApp } from "firebase/app";
import {
  getAuth,
  onAuthStateChanged,
  signInWithEmailAndPassword,
  signOut,
} from "firebase/auth";
import { getFirestore } from "firebase/firestore";
import React from "react";

const firebaseConfig = {
  apiKey: "",
  authDomain: "",
  projectId: "",
  storageBucket: "",
  messagingSenderId: "",
  appId: "",
};

const app = initializeApp(firebaseConfig);
const auth = getAuth(app);
const db = getFirestore(app);

let AuthContext = React.createContext(null);

function AuthProvider({ children }) {
  let [initializing, setInitializing] = React.useState(true);
  let [user, setUser] = React.useState(null);

  let authChanged = React.useCallback((firebaseUser) => {
    if (firebaseUser) setUser(firebaseUser);
    setInitializing(false);

    console.log({ firebaseUser });
  }, []);

  React.useEffect(() => {
    const subscriber = onAuthStateChanged(auth, authChanged);
    return subscriber;
  }, [authChanged]);

  let signin = async (newUser, successCallback, errorCallback) => {
    setInitializing(true);
    try {
      let res = await signInWithEmailAndPassword(
        auth,
        newUser.email,
        newUser.password
      );
      if (res.user) return successCallback();

      return errorCallback("Wrong credentials");
    } catch (error) {
      return errorCallback("Something went Wrong.");
    }
  };

  let signout = async (callback) => {
    await signOut(auth);
    setUser(null);
    callback();
  };

  return (
    <AuthContext.Provider value={{ initializing, user, signin, signout, db }}>
      {children}
    </AuthContext.Provider>
  );
}

export default AuthProvider;
export { AuthContext };

现在我们要做的就是-

import React from "react";
import { AuthContext } from "./authProvider";

function useAuth() {
  return React.useContext(AuthContext);
}

export default useAuth;

现在我们已经创建了钩子,可以开始下一步了
注意:在登录屏幕中使用signin进行严格访问,而signout

react-router-dom沿着

Package 所有需要访问firestore数据的路由,并使用以下组件(请使用react-router-dom作为路由)

export function RequireAuth({ children }) {
  let auth = useAuth();   // we'll create this hook to manage firbase auth and database access
  let location = useLocation(); // hook from react-router-dom

  if (auth.initializing) return null;

  if (!auth.user)
    return <Navigate to="/login" state={{ from: location }} replace />;

  return children;
}

现在,我们将从组件(路由)上的挂钩访问Firestore,如下所示

export default function Documents() {
  const [docs, setDocs] = React.useState([]);
  const [docsLoading, setDocsLoading] = React.useState(true);

  let { user, db } = useAuth();

  React.useEffect(() => {
    async function getUserDocuments() {
      setDocsLoading(true);
      const q = query(collection(db, "docs"), where("author", "==", user.uid));
      const querySnapshot = await getDocs(q);
      const tmpDocs = [];
      querySnapshot.forEach((doc) => {
        tmpDocs.push({ id: doc.id, data: doc.data() });
      });
      setDocs(tmpDocs);
      setDocsLoading(false);
    }

    getUserDocuments();
  }, []);

  return !docsLoading ? (
        docs.map((doc) => (/* show in ui */))
   ) : (
      <div>some loader... until we are loading data</div>
   )
)

我很乐意在评论中回答你的疑问:)

kyks70gy

kyks70gy2#

我也在努力寻找在react web应用程序中从Firestore管理服务器端状态的最佳方法--特别是考虑到Concurrent React的发布。
最后我写了自己的国家管理图书馆。
您可能需要查看@gmcfall/react-firebase-state,它使用侦听器来确保数据是新鲜的,并且在面对许多渲染周期和多个挂载/卸载周期时具有弹性。
你写的
..看起来(onSnapshot)会导致大量读写操作。
我的经验正好相反。我必须减少到服务器的次数,以确保数据是最新的。此解决方案的关键是让组件从保存服务器端状态的本地缓存中“租用”数据。但当数据的声明数量变为零时,实体不会立即从该高速缓存中驱逐。这样,如果用户短暂地导航离开组件,然后返回,或者如果并发渲染开始,数据仍然在那里,并且保证是最新的。

相关问题