Reactjs React Linking.addEventListener在useEffect中运行Firebase登录链接两次

Reactjs React Linking.addEventListener在useEffect中运行Firebase登录链接两次,reactjs,firebase,react-native,Reactjs,Firebase,React Native,我具有以下功能,可使用React Native(Expo)和Firebase对用户进行身份验证: export default function AuthenticateUser() { const user = useStore((state) => state.user); // Gets the user from state const setUser = useStore((state) => state.setUser); const setLoadingUs

我具有以下功能,可使用React Native(Expo)和Firebase对用户进行身份验证:

export default function AuthenticateUser() {
  const user = useStore((state) => state.user); // Gets the user from state
  const setUser = useStore((state) => state.setUser);
  const setLoadingUser = useStore((state) => state.setLoadingUser);
  const [GQL_getOrCreateUser] = useMutation(getOrCreateUser); // GraphQL function

  useEffect(() => {
    let unsubscribe: any;
    let urlHandler: any;

    function handleUrl(event: any) {
      const { url }: { url: string } = event;
      if (url.includes('/account')) {
        const isSignInWithEmailLink = firebase.auth().isSignInWithEmailLink(url);
        if (isSignInWithEmailLink) {
          AsyncStorage.getItem('unverifiedEmail').then((email) => {
            if (email) {
              firebase
                .auth()
                .signInWithEmailLink(email, url)
                .then(() => {
                  // We are signed in
                })
                .catch((error) => {
                  // Failed to sign in
                });
            } else {
              // Missing pending email from AsyncStorage
            }
          });
        }
      };
    }

    function handleLinking(userDetails: User) {
      urlHandler = ({ url }: { url: string }) => {
        handleUrl({ url, userDetails });
      };
      // Listen to incoming deep link when app first opens
      Linking.getInitialURL().then((url) => {
        if (url) {
          handleUrl({ url, userDetails });
        }
      });
      // Listen to incoming deep link while app is open
      Linking.addEventListener('url', urlHandler);
    }

    if (!user) {
      unsubscribe = firebase.auth().onAuthStateChanged((authenticatedUser) => {
        setLoadingUser(false);
        if (authenticatedUser) {
          const uid = authenticatedUser.uid;
          const phoneNumber = authenticatedUser.phoneNumber;
          let email: string;
          if (authenticatedUser.email) {
            email = authenticatedUser.email;
          } else {
            // retreiving email from AsyncStorage. We add it there when requesting a passwordless sign in link email, as recommended by Firebase.
            AsyncStorage.getItem('unverifiedEmail').then((unverifiedEmail) => {
              email = unverifiedEmail ? unverifiedEmail : '';
            });
          }
          const emailVerified = authenticatedUser.emailVerified;
          // Updating user record with GraphQL
          GQL_getOrCreateUser({ variables: { uid, phoneNumber } })
            .then(async (document) => {
              const data = document.data.getOrCreateUser;
              const userDetails = { ...data, phoneNumber, email, emailVerified }
              setUser(userDetails); // Setting the stateful user record
              handleLinking(userDetails); // Handle deeplink
            })
            .catch(() => {
              // GraphQL failed
            });
        }
      });
    }
    return () => {
      unsubscribe?.();
      // Removing event listener;
      Linking.removeEventListener('url', urlHandler);
    };
  }, [GQL_getOrCreateUser, setLoadingUser, setUser, user]);
}
我的问题是sign-in方法运行太频繁,导致意外行为。 我怀疑这是由用户身份验证状态和GraphQL运行触发的重新渲染引起的(GraphQL调用获取或创建用户会导致三次渲染,这似乎是它的行为方式)

我使用deeplinking处理无密码电子邮件登录(
firebase.auth().isSignInWithEmailLink(url)
) 使用Linking.getInitialURL(当深度链接打开应用程序时)或
Linking.addEventListener('URL',handler)
在应用程序已经运行时检测URL

以场景1为例:Linking.getInitialUrl

  • 我点击链接。它要求打开应用程序
  • 应用程序将打开
  • 用户未登录(用户未处于应用程序状态),因此会触发
    if(!user)
    中的代码
  • 用户电子邮件处于异步存储中,因为我们刚刚请求了登录链接电子邮件,当用户请求时,我将其保存
  • GraphQL获取用户并导致另外两个渲染
  • 我使用setUser将用户设置为state并运行handleLinking
  • 由于应用程序已关闭,因此会触发URL的
    getInitialURL
    ,它会正确执行步骤并让我登录。 但是,
    handleLinking
    运行第二次(可能是GraphQL引发的额外两次渲染触发了一个
    Linking.addEventListener
    event to fire?)并返回一个错误,因为无法再次使用登录链接
  • 我认为我的逻辑中有一个基本的流程。这是怎么一回事?如何改进和正确完成这一点?
    谢谢你的帮助

    如果
    useffect
    依赖项中的任何对象发生更改,则
    useffect
    函数将重新运行。因此,如果
    useffect
    回调运行得太频繁,那么应该查看依赖项数组


    重要的是要知道,“更改”可以是一个简单的过程,例如重新实例化一个对象或重新创建一个函数,即使基础值保持不变。

    我在useEffect中看不到任何依赖项@FotisTsakiris看起来更好。它就在那里:
    [GQL\u getOrCreateUser,setLoadingUser,setUser,user]
    我意识到最有可能的核心问题是依赖关系。我也提到过。我想看看是否有人有一个不同的逻辑,这将更好地工作,并解释他们将如何做不同的想法。