Skip to content
This repository has been archived by the owner on Jan 1, 2025. It is now read-only.

Commit

Permalink
Update for browser change in setTimeout() behavior (#1943)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #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
  • Loading branch information
drarmstr authored and facebook-github-bot committed Aug 11, 2022
1 parent 3c9e211 commit 933faf6
Show file tree
Hide file tree
Showing 4 changed files with 13 additions and 19 deletions.
1 change: 1 addition & 0 deletions CHANGELOG-recoil.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
7 changes: 4 additions & 3 deletions packages/recoil-relay/RecoilRelay_Environments.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
* @format
* @oncall recoil
*/

'use strict';

import type {Snapshot, StoreID} from 'Recoil';
Expand Down Expand Up @@ -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());
Expand Down
21 changes: 6 additions & 15 deletions packages/recoil/core/Recoil_Snapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down Expand Up @@ -195,25 +196,22 @@ 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: <T>(RecoilValue<T>) => Loadable<T> = <T>(
recoilValue: RecoilValue<T>,
): Loadable<T> => {
this.checkRefCount_INTERNAL();
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: <T>(RecoilValue<T>) => Promise<T> = <T>(
recoilValue: RecoilValue<T>,
): Promise<T> => {
this.checkRefCount_INTERNAL();
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,
Expand Down Expand Up @@ -245,23 +243,20 @@ 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: <T>(RecoilValue<T>) => RecoilValueInfo<T> = <T>({
key,
}: RecoilValue<T>): RecoilValueInfo<T> => {
this.checkRefCount_INTERNAL();
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);
mapper(mutableSnapshot); // if removing batchUpdates from `set` add it here
return mutableSnapshot;
};

// eslint-disable-next-line fb-www/extra-arrow-initializer
asyncMap: ((MutableSnapshot) => Promise<void>) => Promise<Snapshot> =
async mapper => {
this.checkRefCount_INTERNAL();
Expand All @@ -273,6 +268,8 @@ class Snapshot {
mutableSnapshot.autoRelease_INTERNAL();
return mutableSnapshot;
};

/* eslint-enable fb-www/extra-arrow-initializer */
}

function cloneStoreState(
Expand Down Expand Up @@ -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 = <T>(
recoilState: RecoilState<T>,
newValueOrUpdater: ValueOrUpdater<T>,
Expand All @@ -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 = <T>(recoilState: RecoilState<T>) => {
this.checkRefCount_INTERNAL();
const store = this.getStore_INTERNAL();
Expand All @@ -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<NodeKey, mixed>) => void = (
values: Map<NodeKey, mixed>,
) => {
Expand Down
3 changes: 2 additions & 1 deletion packages/recoil/hooks/Recoil_SnapshotHooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]);

Expand Down

0 comments on commit 933faf6

Please sign in to comment.