From fb9d7eb6b16286ced5c0ffa30fce0af74358a63a Mon Sep 17 00:00:00 2001 From: rory Date: Fri, 7 Nov 2025 10:55:34 -0800 Subject: [PATCH 1/7] Remove useLiveRef from useOnyx --- lib/useLiveRef.ts | 14 -------------- lib/useOnyx.ts | 10 +++++++--- tests/unit/useOnyxTest.ts | 1 - 3 files changed, 7 insertions(+), 18 deletions(-) delete mode 100644 lib/useLiveRef.ts diff --git a/lib/useLiveRef.ts b/lib/useLiveRef.ts deleted file mode 100644 index fb4bef295..000000000 --- a/lib/useLiveRef.ts +++ /dev/null @@ -1,14 +0,0 @@ -import {useRef} from 'react'; - -/** - * Creates a mutable reference to a value, useful when you need to - * maintain a reference to a value that may change over time without triggering re-renders. - */ -function useLiveRef(value: T) { - const ref = useRef(value); - ref.current = value; - - return ref; -} - -export default useLiveRef; diff --git a/lib/useOnyx.ts b/lib/useOnyx.ts index 016eb0f33..7e31fe527 100644 --- a/lib/useOnyx.ts +++ b/lib/useOnyx.ts @@ -11,7 +11,6 @@ import usePrevious from './usePrevious'; import decorateWithMetrics from './metrics'; import * as Logger from './Logger'; import onyxSnapshotCache from './OnyxSnapshotCache'; -import useLiveRef from './useLiveRef'; type UseOnyxSelector> = (data: OnyxValue | undefined) => TReturnValue; @@ -77,8 +76,13 @@ function useOnyx>( const connectionRef = useRef(null); const previousKey = usePrevious(key); - const currentDependenciesRef = useLiveRef(dependencies); - const currentSelectorRef = useLiveRef(options?.selector); + const currentDependenciesRef = useRef(dependencies); + const currentSelectorRef = useRef | undefined>(options?.selector); + + useEffect(() => { + currentDependenciesRef.current = dependencies; + currentSelectorRef.current = options?.selector; + }, [dependencies, options?.selector]); // Create memoized version of selector for performance const memoizedSelector = useMemo(() => { diff --git a/tests/unit/useOnyxTest.ts b/tests/unit/useOnyxTest.ts index afaa6d66f..1438f5b08 100644 --- a/tests/unit/useOnyxTest.ts +++ b/tests/unit/useOnyxTest.ts @@ -409,7 +409,6 @@ describe('useOnyx', () => { expect(result.current[1].status).toEqual('loaded'); selector = (entry: OnyxEntry<{id: string; name: string}>) => `id - ${entry?.id}, name - ${entry?.name} - selector changed`; - // In a react app we expect the selector ref to change during a rerender (see selectorRef/useLiveRef) rerender(undefined); expect(result.current[0]).toEqual('id - test_id, name - test_name - selector changed'); From 272be6c9f17a0de75d58d29e5fb33ffff8497022 Mon Sep 17 00:00:00 2001 From: rory Date: Fri, 7 Nov 2025 10:56:26 -0800 Subject: [PATCH 2/7] Commit package-lock.json diff --- package-lock.json | 57 ++++++++++++++++++++--------------------------- 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/package-lock.json b/package-lock.json index 88eed59dd..c68ebf084 100644 --- a/package-lock.json +++ b/package-lock.json @@ -212,6 +212,7 @@ "integrity": "sha512-N4ntErOlKvcbTt01rr5wj3y55xnIdx1ymrfIr8C2WnM1Y9glFgWaGDEULJIazOX3XM9NRzhfJ6zZnQ1sBNWU+w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@nicolo-ribaudo/eslint-scope-5-internals": "5.1.1-v1", "eslint-visitor-keys": "^2.1.0", @@ -539,7 +540,6 @@ "integrity": "sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.27.1" @@ -557,7 +557,6 @@ "integrity": "sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -574,7 +573,6 @@ "integrity": "sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -591,7 +589,6 @@ "integrity": "sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-skip-transparent-expression-wrappers": "^7.27.1", @@ -610,7 +607,6 @@ "integrity": "sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/traverse": "^7.27.1" @@ -699,7 +695,6 @@ "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", "dev": true, "license": "MIT", - "peer": true, "engines": { "node": ">=6.9.0" }, @@ -813,7 +808,6 @@ "integrity": "sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1014,7 +1008,6 @@ "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.18.6", "@babel/helper-plugin-utils": "^7.18.6" @@ -1084,7 +1077,6 @@ "integrity": "sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1134,7 +1126,6 @@ "integrity": "sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-class-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -1207,7 +1198,6 @@ "integrity": "sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -1225,7 +1215,6 @@ "integrity": "sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1242,7 +1231,6 @@ "integrity": "sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -1260,7 +1248,6 @@ "integrity": "sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1277,7 +1264,6 @@ "integrity": "sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/plugin-transform-destructuring": "^7.28.0" @@ -1295,7 +1281,6 @@ "integrity": "sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1312,7 +1297,6 @@ "integrity": "sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1381,7 +1365,6 @@ "integrity": "sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1430,7 +1413,6 @@ "integrity": "sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1447,7 +1429,6 @@ "integrity": "sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -1482,7 +1463,6 @@ "integrity": "sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1", @@ -1502,7 +1482,6 @@ "integrity": "sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-module-transforms": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -1537,7 +1516,6 @@ "integrity": "sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1606,7 +1584,6 @@ "integrity": "sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1", "@babel/helper-replace-supers": "^7.27.1" @@ -1708,7 +1685,6 @@ "integrity": "sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1809,7 +1785,6 @@ "integrity": "sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -1827,7 +1802,6 @@ "integrity": "sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1914,7 +1888,6 @@ "integrity": "sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1931,7 +1904,6 @@ "integrity": "sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1968,7 +1940,6 @@ "integrity": "sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.27.1" }, @@ -1985,7 +1956,6 @@ "integrity": "sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -2020,7 +1990,6 @@ "integrity": "sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-create-regexp-features-plugin": "^7.27.1", "@babel/helper-plugin-utils": "^7.27.1" @@ -2142,7 +2111,6 @@ "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@babel/helper-plugin-utils": "^7.0.0", "@babel/types": "^7.4.4", @@ -2446,6 +2414,7 @@ "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -3298,6 +3267,7 @@ "integrity": "sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/regexpp": "^4.4.0", "@typescript-eslint/scope-manager": "5.62.0", @@ -3333,6 +3303,7 @@ "integrity": "sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "5.62.0", "@typescript-eslint/types": "5.62.0", @@ -4061,6 +4032,7 @@ "integrity": "sha512-promo4eFwuiW+TfGxhi+0x3czqTYJkG8qB17ZUJiVF10Xm7NLVRSLUsfRTU/6h1e24VvRnXCx+hG7li58lkzog==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/linkify-it": "^5", "@types/mdurl": "^2" @@ -4079,6 +4051,7 @@ "integrity": "sha512-OP+We5WV8Xnbuvw0zC2m4qfB/BJvjyCwtNjhHdJxV1639SGSKrLmJkc3fMnp2Qy8nJyHp8RO6umxELN/dS1/EA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "undici-types": "~6.21.0" } @@ -4106,6 +4079,7 @@ "integrity": "sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@types/prop-types": "*", "csstype": "^3.0.2" @@ -4231,6 +4205,7 @@ "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, "license": "BSD-2-Clause", + "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "6.21.0", "@typescript-eslint/types": "6.21.0", @@ -4654,6 +4629,7 @@ "integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==", "dev": true, "license": "MIT", + "peer": true, "bin": { "acorn": "bin/acorn" }, @@ -5437,6 +5413,7 @@ } ], "license": "MIT", + "peer": true, "dependencies": { "caniuse-lite": "^1.0.30001726", "electron-to-chromium": "^1.5.173", @@ -6944,6 +6921,7 @@ "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -7355,6 +7333,7 @@ "integrity": "sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@rtsao/scc": "^1.1.0", "array-includes": "^3.1.9", @@ -7436,6 +7415,7 @@ "integrity": "sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "aria-query": "^5.3.2", "array-includes": "^3.1.8", @@ -7512,6 +7492,7 @@ "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "array-includes": "^3.1.8", "array.prototype.findlast": "^1.2.5", @@ -7545,6 +7526,7 @@ "integrity": "sha512-QzliNJq4GinDBcD8gPB5v0wh6g8q3SUi6EFF0x8N/BL9PoVs0atuGc47ozMRyOWAKdwaZ5OnbOEa3WR+dSGKuQ==", "dev": true, "license": "MIT", + "peer": true, "engines": { "node": ">=10" }, @@ -9761,6 +9743,7 @@ "integrity": "sha512-NIy3oAFp9shda19hy4HK0HRTWKtPJmGdnvywu01nOqNC2vZg+Z+fvJDxpMQA88eb2I9EcafcdjYgsDthnYTvGw==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/core": "^29.7.0", "@jest/types": "^29.6.3", @@ -11018,6 +11001,7 @@ "integrity": "sha512-a54IwgWPaeBCAAsv13YgmALOF1elABB08FxO9i+r4VFk5Vl4pKokRPeX8u5TCgSsPi6ec1otfLjdOpVcgbpshg==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "argparse": "^2.0.1", "entities": "^4.4.0", @@ -12500,6 +12484,7 @@ "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", "dev": true, "license": "MIT", + "peer": true, "bin": { "prettier": "bin-prettier.js" }, @@ -12705,6 +12690,7 @@ "integrity": "sha512-/3IjMdb2L9QbBdWiW5e3P2/npwMBaU9mHCSCUzNln0ZCYbcfTsGbTJrU/kGemdH2IWmB2ioZ+zkxtmq6g09fGQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "loose-envify": "^1.1.0" }, @@ -12772,6 +12758,7 @@ "integrity": "sha512-0TUhgmlouRNf6yuDIIAdbQl0g1VsONgCMsLs7Et64hjj5VLMCA7np+4dMrZvGZ3wRNqzgeyT9oWJsUm49AcwSQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@jest/create-cache-key-function": "^29.6.3", "@react-native/assets-registry": "0.76.3", @@ -12845,6 +12832,7 @@ "dev": true, "hasInstallScript": true, "license": "MIT", + "peer": true, "peerDependencies": { "react": "*", "react-native": "*" @@ -12973,6 +12961,7 @@ "integrity": "sha512-JWD+aQ0lh2gvh4NM3bBM42Kx+XybOxCpgYK7F8ugAlpaTSnWsX+39Z4XkOykGZAHrjwwTZT3x3KxswVWxHPUqA==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "react-is": "^18.2.0", "react-shallow-renderer": "^16.15.0", @@ -14678,6 +14667,7 @@ "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", + "peer": true, "dependencies": { "@cspotcode/source-map-support": "^0.8.0", "@tsconfig/node10": "^1.0.7", @@ -15074,6 +15064,7 @@ "integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==", "dev": true, "license": "Apache-2.0", + "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" From 58c4414590dc90c4d7bf6345ffa30afc26dc54f1 Mon Sep 17 00:00:00 2001 From: rory Date: Fri, 7 Nov 2025 11:00:15 -0800 Subject: [PATCH 3/7] Remove currentSelectorRef --- lib/useOnyx.ts | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/useOnyx.ts b/lib/useOnyx.ts index 7e31fe527..dcd6f6879 100644 --- a/lib/useOnyx.ts +++ b/lib/useOnyx.ts @@ -77,12 +77,10 @@ function useOnyx>( const previousKey = usePrevious(key); const currentDependenciesRef = useRef(dependencies); - const currentSelectorRef = useRef | undefined>(options?.selector); useEffect(() => { currentDependenciesRef.current = dependencies; - currentSelectorRef.current = options?.selector; - }, [dependencies, options?.selector]); + }, [dependencies]); // Create memoized version of selector for performance const memoizedSelector = useMemo(() => { @@ -95,14 +93,13 @@ function useOnyx>( return (input: OnyxValue | undefined): TReturnValue => { const currentDependencies = currentDependenciesRef.current; - const currentSelector = currentSelectorRef.current; // Recompute if input changed, dependencies changed, or first time const dependenciesChanged = !shallowEqual(lastDependencies, currentDependencies); if (!hasComputed || lastInput !== input || dependenciesChanged) { // Only proceed if we have a valid selector - if (currentSelector) { - const newOutput = currentSelector(input); + if (options?.selector) { + const newOutput = options.selector(input); // Deep equality mode: only update if output actually changed if (!hasComputed || !deepEqual(lastOutput, newOutput) || dependenciesChanged) { @@ -116,7 +113,8 @@ function useOnyx>( return lastOutput; }; - }, [currentDependenciesRef, currentSelectorRef, options?.selector]); + // eslint-disable-next-line react-hooks/exhaustive-deps -- we only need options?.selector, not the entire options object + }, [currentDependenciesRef, options?.selector]); // Stores the previous cached value as it's necessary to compare with the new value in `getSnapshot()`. // We initialize it to `null` to simulate that we don't have any value from cache yet. From 2f03ed87481625dd6bddbb73f7203864f5512b15 Mon Sep 17 00:00:00 2001 From: rory Date: Fri, 7 Nov 2025 11:06:23 -0800 Subject: [PATCH 4/7] Remove currentDependenciesRef --- lib/useOnyx.ts | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/lib/useOnyx.ts b/lib/useOnyx.ts index dcd6f6879..c3aa8f57d 100644 --- a/lib/useOnyx.ts +++ b/lib/useOnyx.ts @@ -76,36 +76,25 @@ function useOnyx>( const connectionRef = useRef(null); const previousKey = usePrevious(key); - const currentDependenciesRef = useRef(dependencies); - - useEffect(() => { - currentDependenciesRef.current = dependencies; - }, [dependencies]); - // Create memoized version of selector for performance const memoizedSelector = useMemo(() => { if (!options?.selector) return null; let lastInput: OnyxValue | undefined; let lastOutput: TReturnValue; - let lastDependencies: DependencyList = []; let hasComputed = false; return (input: OnyxValue | undefined): TReturnValue => { - const currentDependencies = currentDependenciesRef.current; - - // Recompute if input changed, dependencies changed, or first time - const dependenciesChanged = !shallowEqual(lastDependencies, currentDependencies); - if (!hasComputed || lastInput !== input || dependenciesChanged) { + // Recompute if input changed or first time + if (!hasComputed || lastInput !== input) { // Only proceed if we have a valid selector if (options?.selector) { const newOutput = options.selector(input); // Deep equality mode: only update if output actually changed - if (!hasComputed || !deepEqual(lastOutput, newOutput) || dependenciesChanged) { + if (!hasComputed || !deepEqual(lastOutput, newOutput)) { lastInput = input; lastOutput = newOutput; - lastDependencies = [...currentDependencies]; hasComputed = true; } } @@ -114,7 +103,7 @@ function useOnyx>( return lastOutput; }; // eslint-disable-next-line react-hooks/exhaustive-deps -- we only need options?.selector, not the entire options object - }, [currentDependenciesRef, options?.selector]); + }, [dependencies, options?.selector]); // Stores the previous cached value as it's necessary to compare with the new value in `getSnapshot()`. // We initialize it to `null` to simulate that we don't have any value from cache yet. From 298ae3e6224ab4007de713cebf33f89f5870873b Mon Sep 17 00:00:00 2001 From: rory Date: Wed, 19 Nov 2025 17:31:20 -0800 Subject: [PATCH 5/7] Restore useLiveRef for dependencies --- lib/useLiveRef.ts | 17 +++++++++++++++++ lib/useOnyx.ts | 16 ++++++++++++---- 2 files changed, 29 insertions(+), 4 deletions(-) create mode 100644 lib/useLiveRef.ts diff --git a/lib/useLiveRef.ts b/lib/useLiveRef.ts new file mode 100644 index 000000000..869f439db --- /dev/null +++ b/lib/useLiveRef.ts @@ -0,0 +1,17 @@ +import {useRef} from 'react'; + +/** + * Creates a mutable reference to a value, useful when you need to + * maintain a reference to a value that may change over time without triggering re-renders. + * + * @deprecated This hook breaks the Rules of React, and should not be used. + * The migration effort to remove it safely is not currently planned. + */ +function useLiveRef(value: T) { + const ref = useRef(value); + ref.current = value; + + return ref; +} + +export default useLiveRef; diff --git a/lib/useOnyx.ts b/lib/useOnyx.ts index c3aa8f57d..9d67284be 100644 --- a/lib/useOnyx.ts +++ b/lib/useOnyx.ts @@ -11,6 +11,7 @@ import usePrevious from './usePrevious'; import decorateWithMetrics from './metrics'; import * as Logger from './Logger'; import onyxSnapshotCache from './OnyxSnapshotCache'; +import useLiveRef from './useLiveRef'; type UseOnyxSelector> = (data: OnyxValue | undefined) => TReturnValue; @@ -76,25 +77,32 @@ function useOnyx>( const connectionRef = useRef(null); const previousKey = usePrevious(key); + const currentDependenciesRef = useLiveRef(dependencies); + // Create memoized version of selector for performance const memoizedSelector = useMemo(() => { if (!options?.selector) return null; let lastInput: OnyxValue | undefined; let lastOutput: TReturnValue; + let lastDependencies: DependencyList = []; let hasComputed = false; return (input: OnyxValue | undefined): TReturnValue => { - // Recompute if input changed or first time - if (!hasComputed || lastInput !== input) { + const currentDependencies = currentDependenciesRef.current; + + // Recompute if input changed, depedencies changes, or first time + const dependenciesChanged = !shallowEqual(lastDependencies, currentDependencies); + if (!hasComputed || lastInput !== input || dependenciesChanged) { // Only proceed if we have a valid selector if (options?.selector) { const newOutput = options.selector(input); // Deep equality mode: only update if output actually changed - if (!hasComputed || !deepEqual(lastOutput, newOutput)) { + if (!hasComputed || !deepEqual(lastOutput, newOutput) || dependenciesChanged) { lastInput = input; lastOutput = newOutput; + lastDependencies = [...currentDependencies]; hasComputed = true; } } @@ -103,7 +111,7 @@ function useOnyx>( return lastOutput; }; // eslint-disable-next-line react-hooks/exhaustive-deps -- we only need options?.selector, not the entire options object - }, [dependencies, options?.selector]); + }, [currentDependenciesRef, options?.selector]); // Stores the previous cached value as it's necessary to compare with the new value in `getSnapshot()`. // We initialize it to `null` to simulate that we don't have any value from cache yet. From a1100e47fdd6fd610c278164bd565ab0e25ef55e Mon Sep 17 00:00:00 2001 From: rory Date: Wed, 19 Nov 2025 17:32:14 -0800 Subject: [PATCH 6/7] Fix typo --- lib/useOnyx.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/useOnyx.ts b/lib/useOnyx.ts index 9d67284be..d87e9e4e4 100644 --- a/lib/useOnyx.ts +++ b/lib/useOnyx.ts @@ -91,7 +91,7 @@ function useOnyx>( return (input: OnyxValue | undefined): TReturnValue => { const currentDependencies = currentDependenciesRef.current; - // Recompute if input changed, depedencies changes, or first time + // Recompute if input changed, dependencies changed, or first time const dependenciesChanged = !shallowEqual(lastDependencies, currentDependencies); if (!hasComputed || lastInput !== input || dependenciesChanged) { // Only proceed if we have a valid selector From 6cc86e35816b3a443a4082b40c558519b4f1dc11 Mon Sep 17 00:00:00 2001 From: rory Date: Wed, 19 Nov 2025 17:33:30 -0800 Subject: [PATCH 7/7] Remove lint suppression --- lib/useOnyx.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/useOnyx.ts b/lib/useOnyx.ts index d87e9e4e4..f2aa7fa49 100644 --- a/lib/useOnyx.ts +++ b/lib/useOnyx.ts @@ -78,10 +78,13 @@ function useOnyx>( const previousKey = usePrevious(key); const currentDependenciesRef = useLiveRef(dependencies); + const selector = options?.selector; // Create memoized version of selector for performance const memoizedSelector = useMemo(() => { - if (!options?.selector) return null; + if (!selector) { + return null; + } let lastInput: OnyxValue | undefined; let lastOutput: TReturnValue; @@ -95,8 +98,8 @@ function useOnyx>( const dependenciesChanged = !shallowEqual(lastDependencies, currentDependencies); if (!hasComputed || lastInput !== input || dependenciesChanged) { // Only proceed if we have a valid selector - if (options?.selector) { - const newOutput = options.selector(input); + if (selector) { + const newOutput = selector(input); // Deep equality mode: only update if output actually changed if (!hasComputed || !deepEqual(lastOutput, newOutput) || dependenciesChanged) { @@ -110,8 +113,7 @@ function useOnyx>( return lastOutput; }; - // eslint-disable-next-line react-hooks/exhaustive-deps -- we only need options?.selector, not the entire options object - }, [currentDependenciesRef, options?.selector]); + }, [currentDependenciesRef, selector]); // Stores the previous cached value as it's necessary to compare with the new value in `getSnapshot()`. // We initialize it to `null` to simulate that we don't have any value from cache yet.