Closed michelmattos closed 6 years ago
I also have problems figuring out how to make async/await
working properly in effects.
It only works if I make the first function async:
getPosts: async (effects) => {
const result = await fetch('https://jsonplaceholder.typicode.com/posts')
const posts = await result.json()
return state => ({ ...state, posts })
}
But I haven't figured out how do I access state from inside of the effect.
Placing async
anywhere else screws up the state
As far as I can tell that is a bit of a a "dead zone" in effects. They can change and be aware of state in the final (state) => newState method.
There is a "hackish" way of doing this in two stages. it takes advantage of the fact that the final lambda (state) => newState) has acces to the effects from the outer closure AND the state from its own parameter:
effectA [ (effects, param) => ... ]
effectB [
(effects ?) =>
[
(state) =>
effects.effectA(state.foo)
return state (unchanged)
]
]
i.e., effectB gets a state value and calls effectA with it but does NOT return the promise resulting from the effectA call. It then returns state in whatever state its in.
This is a very jury-rigged way of having an effect pull a parameter from state but it will work. Personally I'm fine with having states take parameters that I manually extract from state, as wherever I call an effect from will also have access to state.
@igorbarbashin It's probably because the foremost function can't return a promise but another function (the latter one can be async
)
Ah, I misunderstood you, @igorbarbashin. You're right. The first function needs to be async
.
It is because the effect signature can be Effects => State => State
or Effects => Promise<State => State>
. Since an async
function is the same as () => Promise<any>
then it fufill the latter case.
With that, my example can be rewritten like this:
const wrapComponentWithState = provideState({
initialState: () => ({
posts: null,
postsPending: false
}),
effects: {
setPostsPending: update((state, postsPending) => ({ postsPending })),
setPosts: update((state, posts) => ({ posts })),
getPosts: async effects => {
await effects.setPostsPending(true)
const result = await fetch('https://jsonplaceholder.typicode.com/posts')
const posts = await result.json()
await effects.setPostsPending(false)
return state => ({ ...state, posts })
}
}
})
For some reason, when I return a function at the end of an async function, it doesn't work (the function even don't get called). But when I return the result of another effect (the commented line), it just works.