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.

expose "get" on useRecoilCallback

See original GitHub issue

Hi folks, i’m using useRecoilCallback for running tasks.

it may be needed during a task to get the last updated value of an atom

why not espose the “get” function ?

function get(recoilState) {
      return getRecoilValueAsLoadable(storeRef.current, recoilState);
    }

i’m currently use a fake get (that i suppose is safe because enqueue updaters) that is OK.

const counter = atom({
  key: "counter",
  default: 0,
});

const injectGet = (set) => (recoilState) => {
  return new Promise((resolve) => {
    set(recoilState, (prev: unknown) => {
      resolve(prev);  //TODO handle lodables
      return prev;
    });
  });
};

export const useTestTask = () =>
  useRecoilCallback(({ snapshot, set}) => async () => {
      const get = injectGet(set);
      for (let i = 0; i < 20; i++) {
        let current = await get(counter);
        let old = await snapshot.getLoadable(counter).toPromise();
        console.log("current, old ", current, old);
        set(counter, inc);
      }
    },
    []
  );

But there is a problem if i want to read from async selectors:

const counterSelector= selector({
    key:"counterSelector",
    get: async ({get})=> get(counter)
})

export const useTestTask2 = () =>
  useRecoilCallback(({ snapshot, set}) => async () => {
      const get = injectGet(set);
      for (let i = 0; i < 20; i++) {
        let current = await get(counterSelector);
        let old = await snapshot.getLoadable(counterSelector).toPromise();
        console.log("current, old ", current, old);
        set(counter, inc);
      }
    },
    []
  );

//"cannot set selector while it is pending...."

Patching useRecoilCallback and expose real get solve all the problems

function useRecoilCallback<Args: $ReadOnlyArray<mixed>, Return>(
  fn: CallbackInterface => (...Args) => Return,
  deps?: $ReadOnlyArray<mixed>,
): (...Args) => Return {
  const storeRef = useStoreRef();
  const gotoSnapshot = useGotoRecoilSnapshot();

  return useCallback(
    (...args): Return => {
      // Use currentTree for the snapshot to show the currently committed state
      const snapshot = cloneSnapshot(storeRef.current);

      function set<T>(
        recoilState: RecoilState<T>,
        newValueOrUpdater: (T => T) | T,
      ) {
        setRecoilValue(storeRef.current, recoilState, newValueOrUpdater);
      }

      function reset<T>(recoilState: RecoilState<T>) {
        setRecoilValue(storeRef.current, recoilState, DEFAULT_VALUE);
      }
    
///patch
     function get(recoilState) {
      return getRecoilValueAsLoadable(storeRef.current, recoilState);
    }


  /// ....
}

All ok now:

export const useTestTask3 = () =>
  useRecoilCallback(({ snapshot, set, get}) => async () => {
      for (let i = 0; i < 20; i++) {
        let current = await get(counterSelector).toPromise();
        let old = await snapshot.getLoadable(counterSelector).toPromise();
        console.log("current, old ", current, old);
        set(counter, inc);
      }
    },
    []
  );

Any thoughts?

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

7reactions
ssturcommented, Mar 8, 2021

Wow, thanks @BenjaBobs, that’s exactly what I was after! I should have realized that snapshot has a getLoadable() method.

For reference, here’s what I ended up with:

image

1reaction
salvoravidacommented, Jan 13, 2021

@drarmstr i understand your motivation, but i’m very happy that there is a way to get current state while running tasks, if needed in advanced tasks. (like redux-saga does) Because it would be a limitation for the great power of recoil! Thank you!

Read more comments on GitHub >

github_iconTop Results From Across the Web

useRecoilCallback(callback, deps) | Recoil
Asynchronously read Recoil state without subscribing a React component to re-render if the atom or selector is updated. Deferring expensive lookups to an...
Read more >
Create and Read State for thousands of items using Recoil
To Save the data, I have a button which calls a function. That function just needs to get the ID's, loop through them,...
Read more >
recoil | Yarn - Package Manager
Workaround for React 18 environments with nested renderers that don't support useSyncExternalStore() (#2001, #2010); Expose flag to disable "duplicate atom ...
Read more >
How to update atoms (state) in Recoil.js outside components ...
<RecoilExternalStatePortal> must have been previously loaded in the React tree, ... because it's not temporally dependent like "get" is useRecoilCallback(({ ...
Read more >
Managing Complex State in React with Jared Palmer [explicit]
You should never have State in two places at any time. ... That's going to be scoped and encapsulated but don't expose public...
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