question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Async selector set function

See original GitHub issue

Hello dear Recoil team! Using Recoil for the production application and loving it so far. Just one specific clarification.

In turns out that I can’t have a async selectorFamily set function, example below

const filtersSelector = selectorFamily({
  key: 'filtersSelector',
  get: (filterField: string) => ({ get }) => get(filtersState)[filterField],
  set: (filterField: string) => async ({ set, get }, newVal) => {
    const filterTerms = {
      ...get(filtersState),
      [filterField]: newVal,
    } as FilterTypes;

    const setter = (prevValue: FilterTypes) =>
      ({ ...prevValue, [filterField]: newVal } as FilterTypes);

    set(filtersState, setter);

    const data = await getPhoneNumbers(filterTerms);

    set(phoneNumbersState, data);
  },
});

This code snippet works this way, the filtersState set function works and sets new filter terms, after that the getPhoneNumbers request works (I can see it in the network tab) but the last phoneNumbersState set function does not change the state even though if I write

  set(phoneNumbersState, updateFunc);

the updateFunc gets invoked but I can’t see state updates after that

Thanks in advance!

Issue Analytics

  • State:open
  • Created 3 years ago
  • Reactions:3
  • Comments:11 (7 by maintainers)

github_iconTop GitHub Comments

5reactions
drarmstrcommented, Dec 16, 2020

This issue keeps coming up with users attempting async selector sets and either not having or ignoring static type-checking errors. So, while we are considering if we should add support for this, add dynamic error reporting by throwing errors if async sets are attempted in #777

4reactions
otakustaycommented, Dec 22, 2020

As a state normalization zealot, we very much want an async selector to load a remote data and to pass them forward to atoms like:

const users = atomFamily({key: 'user'});
const list = selectorFamily({
    key: 'users',
    // Want a set function here
    get: ({set}) => async params => {
        const users = await fetchRemoteUsesrs(params);
        for (const user of users) {
            set(users(user.id), user);
        }
        // Normalize it to a list of keys
        return users.map(u => u.id);
    },
});

This requires features similar to this issue, currently we do it in a recoil callback way without suspense support:

const users = atomFamily({key: 'user'});
const list = atomFamily({key: users});
const useListUsers = () => useRecoilCallback(
    ({snapshot, set}) => async params => {
        const current = snapshot.valueMayBe(users(params));

        if (current) {
            return current;
        }

        const users = await fetchRemoteUsesrs(params);
        for (const user of users) {
            set(users(user.id), user);
        }
        // Normalize it to a list of keys
        return users.map(u => u.id);
    },
    []
);

This still raise 2 questions to us:

  1. Is the use of snapshot safe in this way? Does it cause some race condition in edge cases?
  2. How can we cooperate this pattern to suspense’s promise throwing pattern?

Still, is selector and selectorFamily can support this natively, recoil could be a best practice in async state management.

Read more comments on GitHub >

github_iconTop Results From Across the Web

selector(options) - Recoil
get - A function that evaluates the value for the derived state. It may return either a value directly, an asynchronous Promise ,...
Read more >
Update Recoil state from async function - Stack Overflow
I've created a 'selector' from my tasks 'atom', and delegated in a custom 'set' method the aggreation of the new object with the...
Read more >
Use Async Functions in a Recoil Selector - Egghead.io
Instead of just returning a value from a recoil selector, you can return any promise, which means that you can do asynchronous functions...
Read more >
Exploring Asynchronous Requests in Recoil - AppSignal Blog
Recoil selector functions are idempotent, meaning, a given input must return the same output value. In async requests, this becomes critically ...
Read more >
async-selector - npm
An async selector is just like a normal selector except you pass in a function that returns a promise. Until the promise resolves,...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found