From 933faf6212dcfa53c60629167081381d3b4b4dcf Mon Sep 17 00:00:00 2001 From: Douglas Armstrong Date: Thu, 11 Aug 2022 09:40:27 -0700 Subject: [PATCH] Update for browser change in setTimeout() behavior (#1943) Summary: Pull Request resolved: https://github.com/facebookexperimental/Recoil/pull/1943 Resolves #1936 It appears that some browsers changed behavior for `setTimeout(..., 0);`. The timeout previously had a minimum value of 1 but now has new behavior for 0. This caused code ordering changes which broke snapshot auto release for some browsers, though likely only for dev mode when React Fast Refresh was being used (tested by Vija02 with Chrome 104.0.5112.79 and Firefox 103.0.1 using NextJS dev mode). Update the timeouts to workaround this issue. Reviewed By: mrv1k Differential Revision: D38591482 fbshipit-source-id: f868959a4668676c1cd896b95aed6f8da4544237 --- CHANGELOG-recoil.md | 1 + .../recoil-relay/RecoilRelay_Environments.js | 7 ++++--- packages/recoil/core/Recoil_Snapshot.js | 21 ++++++------------- packages/recoil/hooks/Recoil_SnapshotHooks.js | 3 ++- 4 files changed, 13 insertions(+), 19 deletions(-) diff --git a/CHANGELOG-recoil.md b/CHANGELOG-recoil.md index 7baacb0dc..2be7875a8 100644 --- a/CHANGELOG-recoil.md +++ b/CHANGELOG-recoil.md @@ -4,6 +4,7 @@ **_Add new changes here as they land_** - Fix useRecoilSnapshot() with React's Fast Refresh during development (#1891) +- Fix useRecoilSnapshot() and recoil-sync with changed browser behavior starting with Chrome v104 (#1943, #1936) ## 0.7.4 (2022-06-21) diff --git a/packages/recoil-relay/RecoilRelay_Environments.js b/packages/recoil-relay/RecoilRelay_Environments.js index e045d20bf..554ade67e 100644 --- a/packages/recoil-relay/RecoilRelay_Environments.js +++ b/packages/recoil-relay/RecoilRelay_Environments.js @@ -8,6 +8,7 @@ * @format * @oncall recoil */ + 'use strict'; import type {Snapshot, StoreID} from 'Recoil'; @@ -65,16 +66,16 @@ function registerRelayEnvironment( // production the environment registered should never change. const pendingCleanup = cleanupHandlers.get(storeID)?.get(environmentKey); if (pendingCleanup != null) { - clearTimeout(pendingCleanup); + window.clearTimeout(pendingCleanup); cleanupHandlers.get(storeID)?.delete(environmentKey); } return () => { - const cleanupHandle = setTimeout(() => { + const cleanupHandle = window.setTimeout(() => { environmentStore.get(storeID)?.delete(environmentKey); }, 0); const oldHandler = cleanupHandlers.get(storeID)?.get(environmentKey); if (oldHandler != null) { - clearTimeout(oldHandler); + window.clearTimeout(oldHandler); } if (!cleanupHandlers.has(storeID)) { cleanupHandlers.set(storeID, new Map()); diff --git a/packages/recoil/core/Recoil_Snapshot.js b/packages/recoil/core/Recoil_Snapshot.js index 25e060d7d..1d18eef76 100644 --- a/packages/recoil/core/Recoil_Snapshot.js +++ b/packages/recoil/core/Recoil_Snapshot.js @@ -140,7 +140,8 @@ class Snapshot { */ autoRelease_INTERNAL(): void { if (!isSSR) { - window.setTimeout(() => this._release(), 0); + // Use timeout of 10 to workaround Firefox issue: https://github.com/facebookexperimental/Recoil/issues/1936 + window.setTimeout(() => this._release(), 10); } } @@ -195,7 +196,8 @@ class Snapshot { } // We want to allow the methods to be destructured and used as accessors - // eslint-disable-next-line fb-www/extra-arrow-initializer + /* eslint-disable fb-www/extra-arrow-initializer */ + getLoadable: (RecoilValue) => Loadable = ( recoilValue: RecoilValue, ): Loadable => { @@ -203,8 +205,6 @@ class Snapshot { return getRecoilValueAsLoadable(this._store, recoilValue); }; - // We want to allow the methods to be destructured and used as accessors - // eslint-disable-next-line fb-www/extra-arrow-initializer getPromise: (RecoilValue) => Promise = ( recoilValue: RecoilValue, ): Promise => { @@ -212,8 +212,6 @@ class Snapshot { return this.getLoadable(recoilValue).toPromise(); }; - // We want to allow the methods to be destructured and used as accessors - // eslint-disable-next-line fb-www/extra-arrow-initializer getNodes_UNSTABLE: ( { isModified?: boolean, @@ -245,7 +243,6 @@ class Snapshot { // Report the current status of a node. // This peeks the current state and does not affect the snapshot state at all - // eslint-disable-next-line fb-www/extra-arrow-initializer getInfo_UNSTABLE: (RecoilValue) => RecoilValueInfo = ({ key, }: RecoilValue): RecoilValueInfo => { @@ -253,7 +250,6 @@ class Snapshot { return peekNodeInfo(this._store, this._store.getState().currentTree, key); }; - // eslint-disable-next-line fb-www/extra-arrow-initializer map: ((MutableSnapshot) => void) => Snapshot = mapper => { this.checkRefCount_INTERNAL(); const mutableSnapshot = new MutableSnapshot(this, batchUpdates); @@ -261,7 +257,6 @@ class Snapshot { return mutableSnapshot; }; - // eslint-disable-next-line fb-www/extra-arrow-initializer asyncMap: ((MutableSnapshot) => Promise) => Promise = async mapper => { this.checkRefCount_INTERNAL(); @@ -273,6 +268,8 @@ class Snapshot { mutableSnapshot.autoRelease_INTERNAL(); return mutableSnapshot; }; + + /* eslint-enable fb-www/extra-arrow-initializer */ } function cloneStoreState( @@ -379,8 +376,6 @@ class MutableSnapshot extends Snapshot { this._batch = batch; } - // We want to allow the methods to be destructured and used as accessors - // eslint-disable-next-line fb-www/extra-arrow-initializer set: SetRecoilState = ( recoilState: RecoilState, newValueOrUpdater: ValueOrUpdater, @@ -397,8 +392,6 @@ class MutableSnapshot extends Snapshot { }); }; - // We want to allow the methods to be destructured and used as accessors - // eslint-disable-next-line fb-www/extra-arrow-initializer reset: ResetRecoilState = (recoilState: RecoilState) => { this.checkRefCount_INTERNAL(); const store = this.getStore_INTERNAL(); @@ -409,8 +402,6 @@ class MutableSnapshot extends Snapshot { }); }; - // We want to allow the methods to be destructured and used as accessors - // eslint-disable-next-line fb-www/extra-arrow-initializer setUnvalidatedAtomValues_DEPRECATED: (Map) => void = ( values: Map, ) => { diff --git a/packages/recoil/hooks/Recoil_SnapshotHooks.js b/packages/recoil/hooks/Recoil_SnapshotHooks.js index 4199d8adb..f9b1e7ac8 100644 --- a/packages/recoil/hooks/Recoil_SnapshotHooks.js +++ b/packages/recoil/hooks/Recoil_SnapshotHooks.js @@ -202,7 +202,8 @@ function useRecoilSnapshot(): Snapshot { // re-render with the same state. The previous cleanup will then run and // then the new effect will run. We don't want the snapshot to be released // by that cleanup before the new effect has a chance to retain it again. - window.setTimeout(release, 0); + // Use timeout of 10 to workaround Firefox issue: https://github.com/facebookexperimental/Recoil/issues/1936 + window.setTimeout(release, 10); }; }, [snapshot]);