From 7c85fe7b190f0c0ad4d5c0cf38413f436b8e9b09 Mon Sep 17 00:00:00 2001 From: LJ <81748770+elle-j@users.noreply.github.com> Date: Tue, 2 Apr 2024 11:27:18 +0200 Subject: [PATCH] [realm/react] Use the same function reference for the listener when triggering rerender. --- packages/realm-react/src/UserProvider.tsx | 62 +++++++++++++---------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/packages/realm-react/src/UserProvider.tsx b/packages/realm-react/src/UserProvider.tsx index abe4c6d49e..89fee116de 100644 --- a/packages/realm-react/src/UserProvider.tsx +++ b/packages/realm-react/src/UserProvider.tsx @@ -16,7 +16,7 @@ // //////////////////////////////////////////////////////////////////////////// -import React, { createContext, useContext, useEffect, useState } from "react"; +import React, { createContext, useContext, useEffect, useReducer, useState } from "react"; import type Realm from "realm"; import { useApp } from "./AppProvider"; @@ -35,6 +35,21 @@ type UserProviderProps = { children: React.ReactNode; }; +function userWasUpdated(userA: Realm.User | null, userB: Realm.User | null) { + if (!userA && !userB) { + return false; + } else if (userA && userB) { + return ( + userA.id !== userB.id || + userA.state !== userB.state || + userA.accessToken !== userB.accessToken || + userA.refreshToken !== userB.refreshToken + ); + } else { + return true; + } +} + /** * React component providing a Realm user on the context for the sync hooks * to use. A `UserProvider` is required for an app to use the hooks. @@ -42,37 +57,30 @@ type UserProviderProps = { export const UserProvider: React.FC = ({ fallback: Fallback, children }) => { const app = useApp(); const [user, setUser] = useState(() => app.currentUser); + const [, forceUpdate] = useReducer((x) => x + 1, 0); // Support for a possible change in configuration - if (app.currentUser?.id != user?.id) { - setUser(app.currentUser); + const currentUser = app.currentUser; + if (userWasUpdated(user, currentUser)) { + setUser(currentUser); } useEffect(() => { - const event = () => { - let userHasChanged = false; - const currentUser = app.currentUser; - if (currentUser && user) { - userHasChanged = - currentUser.id !== user.id || - currentUser.state !== user.state || - currentUser.accessToken !== user.accessToken || - currentUser.refreshToken !== currentUser.refreshToken; - } else if (currentUser || user) { - userHasChanged = true; - } - - if (userHasChanged) { - setUser(app.currentUser); - } - }; - user?.addListener(event); - app?.addListener(event); - return () => { - user?.removeListener(event); - app?.removeListener(event); - }; - }, [user, app]); + app.addListener(forceUpdate); + + return () => app.removeListener(forceUpdate); + }, [app]); + + useEffect(() => { + user?.addListener(forceUpdate); + + return () => user?.removeListener(forceUpdate); + + /* + eslint-disable-next-line react-hooks/exhaustive-deps + -- We should depend on `user.id` rather than `user` as the ID will indicate a new user in this case. + */ + }, [user?.id]); if (!user) { if (typeof Fallback === "function") {