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

[Library Usage] Multiple states changes for an action /\ Action trigger after side effect #775

Open
jtouzy opened this issue Nov 22, 2024 · 1 comment

Comments

@jtouzy
Copy link

jtouzy commented Nov 22, 2024

I wanted to ask about how to implement some specific behaviour, that can happen very often in basic apps.

Here's the scenario : Let's imagine we're in a Login module.

  • When I tap on "Login" button, I want to disable my whole UI. For this, I need to update the state, once ;
  • In the same time, I will call my signIn() suspend function that will call whatever it needs to be logged => call it the side effect ;
  • After this suspend call, I want to update my state again, in any case of error message or something ;

I have multiple problems with this approach with the current implementation :

  • Main problem is I can't send multiple state changes. I agree, this should never be the case in POV of the redux pattern, but at least, we should be able to trigger a new action after a side effect (that's how composable-architecture handle this problem - a redux function must return a side effect) ;
  • Related to this, after a suspend sideEffect, the state could have been modified by other actions during this period of time, and we don't know about it. The state.snapshot stays the same as before, it's pretty normal. But it leads to some blockers ;

Do you have an implementation solution for this kind of behaviour or it was not planned for the library at all?

Example:

on<LoginAction.SignInTapped> { _, state ->
   // Here I want to update my state first, to disable UI
   dependencies
      .signIn(state.snapshot.email.text, state.snapshot.password.text)
      .fold(
         onSuccess = { state.noChange() },
         onFailure = {
            // Here I want to update my state to set an error message
            state.noChange()
         }
      )
}
@befrvnk
Copy link
Contributor

befrvnk commented Jan 15, 2025

With FlowRedux, you can still display a loading state while loading the content. You have two options:

1. Within the content state
You can use condition() and onEnter to load the content within the same state.

interface State

data class Content(
  val loading: Boolean = false,
  val result: Result? = null,
) : State

data object Error

inState<Content> {
  onEnter { state ->
    state.mutate { copy(loading = true) }
  }
  condition({ it.loading }) {
    onEnter { state ->
      val result = loadContent()
      when (result) {
        is Success -> state.mutate { copy(result = result, loading = false) }
        is Error -> state.override { Error }
      }
    }
  }
}

2. With a sub-state for loading

With this solution you create an extra sub-state for loading. In this state you load the content with onEnter. A disadvantage is that it's different from the content state.

interface State

data object Loading

data class Content(
  val result: Result,
) : State

data object Error

inState<Loading> {
  onEnter { state ->
    val result = loadContent()
    when (result) {
      is Success -> state.mutate { copy(result = result) }
      is Error -> state.override { Error }
    }
  }
}

If you want to receive actions and execute them in both solutions, you can use execution policy to specify what should happen when an action is currently running and the state machine receives another one.
Please let us know if you still have questions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

No branches or pull requests

2 participants