gordonbrander / spellcaster

Reactive signals UI library
MIT License
58 stars 2 forks source link

Proposal: Saga-style effects via async generator functions #28

Closed gordonbrander closed 8 months ago

gordonbrander commented 10 months ago

Status: speculative.

This PR changes the type of effects to be async generator functions yielding/returning Msg. Yield receives the current state, allowing multi-step effects to sample state and make decisions about how to proceed.

Since the store and effects are a feedback loop, this is functionally equivalent to using Promise-based effects and recursion. However, it may open up more familiar control flow opportunities. YMMV.

Example

Basic example of a single side-effect. Not all that different from using async functions.

async function* fetchUser(msg) {
  try {
    const user = await ApiService.fetchUser(msg.userId)
    return Msg.succeedFetchUser(user)
  } catch (e) {
    return Msg.failFetchUser(e.message)
  }
}

A more complex multi-step example:

async function* fetchProfile(msg) {
  try {
    const user = await ApiService.fetchUser(msg.userId)
    yield Msg.succeedFetchUser(user)
  } catch (e) {
    yield Msg.failFetchUser(e.message)
    return Msg.failFetchProfile()
  }

  try {
    const profileFeed = await ApiService.fetchProfileFeed(msg.userId)
    yield Msg.succeedFetchProfileFeed(profileFeed)
  } catch (e) {
    yield Msg.failFetchProfileFeed(e.message)
    return Msg.failFetchProfile()
  }

  return Msg.succeedFetchProfile()
}