Replies: 2 comments 6 replies
-
I should document managing multiple asynchronous atoms better. Yes. In Zedux, asynchrony is managed outside atom evaluation. This gives you full control over asynchrony at the cost of having to exercise that control. Awaiting An early prototype of Zedux actually made atoms asynchronous like Recoil/Jotai. We got rid of it 'cause we needed this extra control. Btw you can forward promises if you want to use suspense with return api().setPromise(nameInstance.promise) Also with exports, one thing to watch out for is something force-destroying the const otherAtom = atom("other", () => {
const { getInstance } = injectAtomGetters();
getInstance(nameAtom); // register a graph dependency, but don't use it here
return api().setExports({
sayName: async () => {
const nameInstance = getInstance(nameAtom); // get the instance here
await nameInstance.promise;
console.log(nameInstance.getState());
}
});
}); If the atom takes params, it may be more convenient to pass the possibly-destroyed instance directly to Here's an example combining all these tips. In practice, this is up to you. I always guard against force-destruction in case someone else comes along and force-destroys an atom. But you could of course make it a convention in your app to just never force-destroy. You can get along without that feature. |
Beta Was this translation helpful? Give feedback.
-
I see a recipe in docs for async -> sync atom dependency. How would one handle a chain of two query atoms, where the second one depends on the first one, i.e. async -> async composition? Concrete example: I need to get an access token via an async call. Then, I need to use that access token to fetch a resource. I want suspense to wait for both operations before showing the resource without state tearing or flickering between them. In pseudocode this is what I want: const resourceAtom = atom('resource', ({ get }) => {
const accessToken = await get(accessTokenAtom);
const resource = await fetch('/resource', accessToken);
return resource;
}); A naive I wrote a helper like this: export const injectPromiseChain = (nodeDeps, promiseFactory, deps, config) => {
const nodes = nodeDeps.map((node) =>
is(node, AtomTemplateBase) ? injectAtomInstance(node) : node
);
const rawValues = nodes.map((node) => node.get());
return injectPromise(
async (params) => {
await Promise.all(nodes.map((node) => node.promise).filter((p) => p));
if (params.controller?.signal.aborted) {
return undefined;
}
return promiseFactory(rawValues.map((value) => ("data" in value ? value.data : value)), params);
},
rawValues.concat(deps ?? []),
config
);
};
const resourceAtom = atom('resource', () => {
return injectPromiseChain([accessTokenAtom], ([accessToken], params) => {
return await fetch('/resource', accessToken)
});
}); Haven't tested it yet, but does anyone know if there's a more official way to do this? |
Beta Was this translation helpful? Give feedback.
-
Is this the preferred way to write it in zedux because i didn't see (or miss) the pattern in docs.
https://codesandbox.io/s/zedux-async-function-orx3sd?file=/src/App.tsx
Beta Was this translation helpful? Give feedback.
All reactions