From a69da1220e777be149e24f937090d294fdeed8ef Mon Sep 17 00:00:00 2001 From: Mike Hernas Date: Tue, 21 Nov 2023 21:43:12 +0100 Subject: [PATCH 1/3] Possible solution for exhausive deps --- packages/realm-react/src/useQuery.tsx | 31 ++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/packages/realm-react/src/useQuery.tsx b/packages/realm-react/src/useQuery.tsx index 673f80a1cf..51cdb16e85 100644 --- a/packages/realm-react/src/useQuery.tsx +++ b/packages/realm-react/src/useQuery.tsx @@ -25,12 +25,36 @@ type RealmClassType = { new (...args: any): T }; type QueryCallback = (collection: Realm.Results) => Realm.Results; type DependencyList = ReadonlyArray; +function simplifyArguments>( + typeOrQuery: string | RealmClassType | QueryCallback, + queryOrDeps: QueryCallback | DependencyList = (collection: Realm.Results) => collection, + depsOrType: DependencyList | string | RealmClassType = [], +): { type: string | RealmClassType; query: QueryCallback; deps: DependencyList } { + if (Array.isArray(queryOrDeps)) { + return { + type: depsOrType as unknown as string | RealmClassType, + query: typeOrQuery as unknown as QueryCallback, + deps: queryOrDeps as unknown as DependencyList, + }; + } + return { + type: typeOrQuery as unknown as string | RealmClassType, + query: queryOrDeps as unknown as QueryCallback, + deps: depsOrType as unknown as DependencyList, + }; +} /** * Generates the `useQuery` hook from a given `useRealm` hook. * @param useRealm - Hook that returns an open Realm instance * @returns useObject - Hook that is used to gain access to a {@link Realm.Collection} */ export function createUseQuery(useRealm: () => Realm) { + function useQuery(query: QueryCallback, deps: DependencyList, type: string): Realm.Results>; + function useQuery>( + query: QueryCallback, + deps: DependencyList, + type: RealmClassType, + ): Realm.Results>; function useQuery( type: string, query?: QueryCallback, @@ -42,10 +66,11 @@ export function createUseQuery(useRealm: () => Realm) { deps?: DependencyList, ): Realm.Results; function useQuery>( - type: string | RealmClassType, - query: QueryCallback = (collection: Realm.Results) => collection, - deps: DependencyList = [], + typeOrQuery: string | RealmClassType | QueryCallback, + queryOrDeps: QueryCallback | DependencyList = (collection: Realm.Results) => collection, + depsOrType: DependencyList | string | RealmClassType = [], ): Realm.Results { + const { type, query, deps } = simplifyArguments(typeOrQuery, queryOrDeps, depsOrType); const realm = useRealm(); // We need to add the type to the deps, so that if the type changes, the query will be re-run. From 110815aca067313267a4651bbc69c3f294833121 Mon Sep 17 00:00:00 2001 From: Mike Hernas Date: Thu, 23 Nov 2023 16:02:08 +0100 Subject: [PATCH 2/3] Add test & fix missing dep in RealmProvider --- packages/realm-react/.eslintrc.json | 7 ++++++- packages/realm-react/src/RealmProvider.tsx | 2 +- .../src/__tests__/useQueryHook.test.tsx | 18 ++++++++++++++++++ packages/realm-react/src/useQuery.tsx | 1 + 4 files changed, 26 insertions(+), 2 deletions(-) diff --git a/packages/realm-react/.eslintrc.json b/packages/realm-react/.eslintrc.json index e4ad48b12e..c169e770f0 100644 --- a/packages/realm-react/.eslintrc.json +++ b/packages/realm-react/.eslintrc.json @@ -8,7 +8,12 @@ "rules": { "@typescript-eslint/explicit-function-return-type": "off", "react-hooks/rules-of-hooks": "error", - "react-hooks/exhaustive-deps": "warn", + "react-hooks/exhaustive-deps": [ + "warn", + { + "additionalHooks": "(^useQuery$)" + } + ], "jsdoc/check-tag-names": "off", "jsdoc/require-jsdoc": "off", "jsdoc/require-returns": "off", diff --git a/packages/realm-react/src/RealmProvider.tsx b/packages/realm-react/src/RealmProvider.tsx index 879fcd8b41..b00ef4cb2e 100644 --- a/packages/realm-react/src/RealmProvider.tsx +++ b/packages/realm-react/src/RealmProvider.tsx @@ -123,7 +123,7 @@ export function createRealmProvider( if (realmRef) { realmRef.current = realm; } - }, [realm]); + }, [realm, realmRef]); useEffect(() => { const realmRef = currentRealm.current; diff --git a/packages/realm-react/src/__tests__/useQueryHook.test.tsx b/packages/realm-react/src/__tests__/useQueryHook.test.tsx index 8966da8f0e..c8f9c6a621 100644 --- a/packages/realm-react/src/__tests__/useQueryHook.test.tsx +++ b/packages/realm-react/src/__tests__/useQueryHook.test.tsx @@ -112,4 +112,22 @@ describe("useQueryHook", () => { expect(collection[99]).toBe(undefined); }); + + it("should support reversed order of arguments for exhausive deps", () => { + // Eslint will trigger warning here with + // 120:92 warning React Hook useQuery has a missing dependency: 'gender'. Either include it or remove the dependency array react-hooks/exhaustive-deps + // which is correct behaviour. + const { result } = renderHook( + ({ gender }) => useQuery((objects) => objects.filtered("gender = $0", gender), [], "dog"), + { + initialProps: { gender: "male" }, + }, + ); + const collection = result.current; + + expect(collection).not.toBeNull(); + expect(collection.length).toBe(2); + expect(collection[0]).toMatchObject(testDataSet[0]); + expect(collection[1]).toMatchObject(testDataSet[3]); + }); }); diff --git a/packages/realm-react/src/useQuery.tsx b/packages/realm-react/src/useQuery.tsx index 51cdb16e85..d9671bca62 100644 --- a/packages/realm-react/src/useQuery.tsx +++ b/packages/realm-react/src/useQuery.tsx @@ -87,6 +87,7 @@ export function createUseQuery(useRealm: () => Realm) { // We want the user of this hook to be able pass in the `query` function inline (without the need to `useCallback` on it) // This means that the query function is unstable and will be a redefined on each render of the component where `useQuery` is used // Therefore we use the `deps` array to memoize the query function internally, and only use the returned `queryCallback` + // eslint-disable-next-line react-hooks/exhaustive-deps const queryCallback = useCallback(query, [...deps, ...requiredDeps]); // If the query function changes, we need to update the cachedCollection From cc5691857304be979315a6b99f3b64cf659edb08 Mon Sep 17 00:00:00 2001 From: Mike Hernas Date: Thu, 23 Nov 2023 16:31:28 +0100 Subject: [PATCH 3/3] Export useQuery & useObject --- packages/realm-react/src/index.tsx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/realm-react/src/index.tsx b/packages/realm-react/src/index.tsx index 35faee8e0d..280ec50e4d 100644 --- a/packages/realm-react/src/index.tsx +++ b/packages/realm-react/src/index.tsx @@ -218,3 +218,5 @@ export { useUser, UserProvider } from "./UserProvider"; export * from "./useAuth"; export * from "./useEmailPasswordAuth"; export * from "./types"; +export * from "./useQuery"; +export * from "./useObject";