Skip to content

Commit

Permalink
Resolve promise on server side rendering as endBatch is only called o…
Browse files Browse the repository at this point in the history
…n useEffect (facebookexperimental#2073)

Summary:
Reference Issue: [https://github.com/facebookexperimental/Recoil/issues/1960](https://github.com/facebookexperimental/Recoil/issues/1960)

The function sendEndOfBatchNotifications is only executed on useEffect as below:
```
useEffect(() => {
    // enqueueExecution runs this function immediately; it is only used to
    // manipulate the order of useEffects during tests, since React seems to
    // call useEffect in an unpredictable order sometimes.
    Queue.enqueueExecution('Batcher', () => {
      endBatch(storeRef.current);
    });
  });
```

This caused the SSR usage of async selector to get stuck in infinite loading.

With this PR, we make sure that when the original promise is resolved, we resolve the `handleLoadable` promise as well. Thus making it compatible with SSR rendering

Pull Request resolved: facebookexperimental#2073

Differential Revision: https://www.internalfb.com/diff/D40948099?entry_point=27

Pulled By: drarmstr

fbshipit-source-id: 9ac77a898ecd118005d87ddf0a461478cf498488
  • Loading branch information
tirthbodawala authored and facebook-github-bot committed Nov 8, 2022
1 parent cba7838 commit 56e4bfd
Show file tree
Hide file tree
Showing 2 changed files with 15 additions and 1 deletion.
2 changes: 2 additions & 0 deletions CHANGELOG-recoil.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@

## UPCOMING
**_Add new changes here as they land_**

- Fix potential unhandled promise rejection in `useRecoilCallback()` (#2075)
- Add OSS support for GateKeeper feature toggling via `RecoilEnv.RECOIL_GKS_ENABLED` (#2078)
- Fix resolving suspense of async selectors used with SSR (#2073, #1960)

## 0.7.6 (2022-10-06)

Expand Down
14 changes: 13 additions & 1 deletion packages/recoil/hooks/Recoil_Hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,11 @@ const useRetain = require('./Recoil_useRetain');
const {useCallback, useEffect, useMemo, useRef, useState} = require('react');
const {setByAddingToSet} = require('recoil-shared/util/Recoil_CopyOnWrite');
const differenceSets = require('recoil-shared/util/Recoil_differenceSets');
const {isSSR} = require('recoil-shared/util/Recoil_Environment');
const err = require('recoil-shared/util/Recoil_err');
const expectationViolation = require('recoil-shared/util/Recoil_expectationViolation');
const gkx = require('recoil-shared/util/Recoil_gkx');
const isPromise = require('recoil-shared/util/Recoil_isPromise');
const recoverableViolation = require('recoil-shared/util/Recoil_recoverableViolation');
const useComponentName = require('recoil-shared/util/Recoil_useComponentName');

Expand All @@ -59,7 +61,17 @@ function handleLoadable<T>(
return loadable.contents;
} else if (loadable.state === 'loading') {
const promise = new Promise(resolve => {
storeRef.current.getState().suspendedComponentResolvers.add(resolve);
const suspendedComponentResolvers =
storeRef.current.getState().suspendedComponentResolvers;
suspendedComponentResolvers.add(resolve);

// SSR should clear out the wake-up resolver if the Promise is resolved
// to avoid infinite loops. (See https://github.com/facebookexperimental/Recoil/pull/2073)
if (isSSR && isPromise(loadable.contents)) {
loadable.contents.finally(() => {
suspendedComponentResolvers.delete(resolve);
});
}
});

// $FlowExpectedError Flow(prop-missing) for integrating with tools that inspect thrown promises @fb-only
Expand Down

0 comments on commit 56e4bfd

Please sign in to comment.