Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cannot get values of other pending selectors while setting a selector. #780

Open
a-tonchev opened this issue Dec 3, 2020 · 2 comments
Open
Assignees
Labels
bug Something isn't working

Comments

@a-tonchev
Copy link

a-tonchev commented Dec 3, 2020

I get this error message when I try to set values with useSetRecoilState, before I use the useRecoilValue/useRecoilState.

image

The selector behind useSetRecoilState is setting value on atom that has async default value.

When I call the useRecoilValue(itemsInCartStore); somewhere before setting its values, I don't get any more this error.

I think that when the atom is called, the Suspence above it does first wait for it to get its value and then the setter has no problems, but when this is not the case the setter just try to set value on the atom before it is initialized. It makes of course sense, but is there any better way for such use-case? My goal is to synchronise in background the values of all the atoms before the user even need to use them.

My Code:

I have async LocalForage where I get all the default values like this:

I have main atom where to load the local storage data

export const ordersLocalStorageData = atom({
  key: 'ordersLocalStorageData',
  default: selector({
    key: 'ordersLocalStorageData/default',
    get: async () => {
      const storage = await LocalForage.getItems([
        StorageEnums.itemsInWishList,
        StorageEnums.itemsInCart,
        StorageEnums.localOrders,
        StorageEnums.myOrders,
      ]);
      return storage || {};
    },
  }),
});

Each atom store get its own default value then from the main init atom:

export const itemsInCartStore = atom({
  key: 'itemsInCart',
  default: selector({
    key: 'itemsInCart/default',
    get: ({ get }) => {
      const localStorageData = get(ordersLocalStorageData);
      return localStorageData[StorageEnums.itemsInCart] || [];
    },
  }),
});

The idea is to get all items from the indexed DB at once, and not make request by each atom separately. (even if request to local indexed DB is quite cheap and fast, still....)

In background of all user actions I synchronize the server with the local state of the user. I use similar selector:

As soon I try to get or set this atom in my setter, the error comes

export const setCachedItemsSelector = selector({
  key: 'setCachedItemsSelector',
  get: ({ get }) => get(cachedItemsStore),
  set: (
    {
      get,
      set,
    },
    someData,
  ) => {
        // Do something with someData...
         const cachedItemsInCart = get(itemsInCartStore);
        get(itemsInCartStore, someNewData);
});
@a-tonchev
Copy link
Author

a-tonchev commented Dec 3, 2020

Just created a codeSandbox example:

https://codesandbox.io/s/react-recoil-forked-5p87f?file=/src/App.js

@drarmstr drarmstr self-assigned this Dec 4, 2020
@drarmstr drarmstr added the bug Something isn't working label Dec 4, 2020
@drarmstr drarmstr changed the title Error: Tried to set the value of Recoil selector itemsInCart__withFallback using an updater function, but it is an async selector in a pending or error state; this is not supported. Cannot get values of other pending selectors while setting a selector. Dec 4, 2020
@drarmstr
Copy link
Contributor

drarmstr commented Dec 4, 2020

This is related to #439 and #762. Selector set()'s are currently synchronous and can't handle getting other atoms in a pending or error state. Async selector sets may help solve this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants