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

Unable to await an async writable atom from another async writable atom #685

Closed
acusti opened this issue Sep 1, 2021 · 3 comments · Fixed by #689
Closed

Unable to await an async writable atom from another async writable atom #685

acusti opened this issue Sep 1, 2021 · 3 comments · Fixed by #689
Assignees
Labels
enhancement New feature or request

Comments

@acusti
Copy link

acusti commented Sep 1, 2021

i am using jotai for my auth flow and have a number of async writable (write-only) atoms. some of them depend on other async writable atoms. i tried to use await set(otherAsyncAtom); to trigger the other async atom and wait for it to complete, but execution continues immediately (no awaiting).

here’s a simple (contrived) demonstration of the issue, using console.log to show when each part of the async writable atoms execute: https://codesandbox.io/s/jotai-await-async-set-2esbb

is this the expected behavior? and if so, is there a different way to accomplish what i am looking for? thanks for all of your assistance and for an excellent library!

@dai-shi
Copy link
Member

dai-shi commented Sep 2, 2021

This is the expected behavior but we are not happy with it.
Related issues: #607, old #204.

I made it return a promise once before v1. It didn't feel like a right abstraction, as it returns promise conditionally.
Implementation-wise, it was too tricky. The issue is, from the library perspective, we don't know if otherAsyncAtom is async or not in advance.

As I understand your expectation, I would like to revisit this along with #607.
(Now, I think there's a more straightforward way. void | Promise<void> seems fine.)


Meanwhile, the workaround I can think of is the use of traditional callback.

const fooAtom = atom(null, async (get, set, callback) => {
  await resolveAfter2Seconds();
  console.log("END fooAtom write (should be 3rd)");
  callback();
});

const barAtom = atom(null, (get, set) => {
  set(fooAtom, () => {
    console.log("END barAtom write (should be 4th)");
  });
});

But, this is ugly...

@dai-shi dai-shi added the enhancement New feature or request label Sep 2, 2021
@dai-shi dai-shi self-assigned this Sep 2, 2021
@acusti
Copy link
Author

acusti commented Sep 2, 2021

i agree that having set(writeAtom) return void | Promise<void> depending on whether or not it returns a promise (e.g. is async) makes sense. i expected the same from useAtom also:

  const [, triggerAction] = useAtom(triggerActionAtom);
  const [isActionComplete, setIsActionComplete] = useState(false);

  const handleClick = useCallback(() => {
    const executeAction = async () => {
      await triggerAction();
      setIsActionComplete(true);
    };

    executeAction();
  }, [triggerAction]);

but now i’m thinking that await triggerAction(); has the same problem as await set(triggerActionAtom);


considering that making an async write-only atom means you are actually returning a value (Promise<void>), i decided to try implementing these as read-only atoms, where the read function is a thunk:

function resolveAfter2Seconds() {
  console.log("START resolveAfter2Seconds (should be 1st)");
  return new Promise((resolve) => {
    setTimeout(function () {
      resolve("slow");
      console.log("END resolveAfter2Seconds (should be 2nd)");
    }, 2000);
  });
}

const fooAtom = atom((get) => async () => {
  await resolveAfter2Seconds();
  console.log("END fooAtom read (should be 3rd)");
});

const barAtom = atom((get) => async () => {
  await get(fooAtom)();
  console.log("END barAtom read (should be 4th)");
});

it seems to work, and using a thunk means that the returned function can take arguments. however, not being able to invoke set(...) from the resulting actions is a pretty major limitation. in codesandbox: https://codesandbox.io/s/jotai-await-async-get-forked-m1ncn

@dai-shi
Copy link
Member

dai-shi commented Sep 2, 2021

Yea, it's the same problem (and the same fix). Note read works for async, but no side effects are allowed in read.

I will work on it, and will ask you to test it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants