简体   繁体   English

如何在“setUsername”场景中最小化 firestore 读取?

[英]How can I minimize firestore reads in the "setUsername" scenario?

the code I have now created is working, but I think it is somehow suboptimal, as it does to many database reads As far as I understand it, the "onAuthStateChange" can be understood like an useEffect hook, which gets called whenever the user authentication state changes (login, logout).我现在创建的代码正在运行,但我认为它在某种程度上不是最理想的,因为它对许多数据库读取都是如此 据我了解,“onAuthStateChange”可以理解为 useEffect 挂钩,只要用户身份验证就会调用它state 更改(登录、注销)。 Whenever this happens, the database should be checked for the username which has been chosen by the user.每当发生这种情况时,都应检查数据库以查找用户选择的用户名。 But if I take a look at the console the docSnap is logged a fair amount of times which to me indicates that the function gets called more often than just when the user logs in / logs out.但是,如果我看一下控制台,docSnap 会被记录很多次,这对我来说表明 function 比用户登录/注销时更频繁地被调用。

在此处输入图像描述

Context Component上下文组件

import { createContext } from "react/cjs/react.production.min";
import { onAuthStateChanged } from "firebase/auth";
import { doc, getDoc } from "firebase/firestore";
import { auth,db } from "./firebase";
import { useState, useEffect } from "react";

export const authContext = createContext({
  user: "null",
  username: "null",
});

export default function AuthenticationContext(props) {
  const [googleUser, setGoogleUser] = useState(null);
  const [username, setUsername] = useState(null);
  const [userID, setUserID] = useState(null);

  onAuthStateChanged(auth, (user) => {
    if (user) {
      setGoogleUser(user.displayName);
      setUserID(user.uid);
      getUsername();
    } else {
      setGoogleUser(null);
    }
  });


    const getUsername = async () => {
      const docRef = doc(db, `users/${userID}`);
      const docSnap = await getDoc(docRef);
      if(docSnap.exists()){
        setUsername(docSnap.data().username);
      }
      else{
        setUsername(null);
      }
    };
  

  return (
    <authContext.Provider value={{ user: googleUser, username: username }}>
      {props.children}
    </authContext.Provider>
  );
}

What is more, is that when I login with google and submit a username, the components do not get reevaluated - so a refresh is necessary in order for all the changes to take effect, this has something to do with me not updating state in the submitHandler of the login page.更重要的是,当我使用 google 登录并提交用户名时,组件不会被重新评估 - 因此需要刷新才能使所有更改生效,这与我没有更新 state 在登录页面的submitHandler。 If you have some ideas on how I can do this more professionally please let me hear them.如果您对我如何更专业地做到这一点有一些想法,请告诉我。 Thank you in advance!先感谢您!

Submit Handler on Login Page在登录页面提交处理程序

const submitHandler = async (event) => {
    event.preventDefault();
    console.log(auth.lastNotifiedUid);
    await setDoc(doc(db, "users", auth.lastNotifiedUid), {
      displayName: user,
      username: username,
    });
    await setDoc(doc(db, "usernames", username), { uid: auth.lastNotifiedUid });
  };

As pointed out in the comments by Dharmaraj, you set multiple subscriptions to the authentication state. This is because you call onAuthStateChanged in the body of your component, so it is executed on every render.正如 Dharmaraj 的评论中所指出的,您设置了对身份验证 state 的多个订阅。这是因为您在组件主体中调用onAuthStateChanged ,所以它会在每次渲染时执行。

To avoid this, you should wrap the function in useEffect so that you only subscribe on component mounting, and unsubscribe on unmounting:为避免这种情况,您应该将 function 包装在useEffect中,以便您仅订阅组件安装,并取消订阅卸载:

export default function AuthenticationContext(props) {
  /* ... */
  React.useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => { /* ... */ });
    return unsubscribe;
  }, []);
  /* ... */
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM