- Added
wasmJs
target. - Potentially fix a crash for
onEnterStateMachine
where an action could be dispatched to the sub state machine during cancellation. - Updated to Kotlin 2.0.0.
- Updated to Coroutines 1.8.1.
- Fix deadlock when using ExecutionPolicy.ORDERED.
- Reduce allocations in
rememberStateAndDispatch
. Thanks to @hoc081098 for teh contribution. - Updated to Kotlin 1.9.22.
- Added new
condition
block that allows specifying additional condition for a state. The block supports all the same methods thatinState
supports.spec { inState<MyState> { // general onEnter/onAction/... methods condition({ state -> state.value == "condition" }) { // onEnter/onAction/... methods that will only be triggered when the condition is true } } }
- Added new
untilIdentityChanges
block. This allows to give a state object an identity like an id and will re-trigger anything running in that block whenever the identity changes.spec { inState<MyState> { // general onEnter/onAction/... methods untilIdentityChanges({ state -> state.searchQuery }) { // triggered whenever `searchQuery` changes onEnterEffect { state -> sendAnalyticsEvent(state.searchQuery) } // whenever `searchQuery` changes the collection is stopped and a new flow is built and collected collectWhileInState({ state -> loadSearchResults(state.searchQuery )}) { result, state -> // update state based on result } } } }
- The internals of FlowRedux have been completely rewritten and simplified. The library behavior is now much more consistent and predictable.
- Cancellation of a running block like
collectWhileInState
is now guaranteed to happen before anything in the new state starts.
- The
collectWhileInState
method that has a lambda parameter to build the collectedFlow
. now receivesS
instead ofFlow<S>
as its parameter. - The compose artifact is now a multiplatform library with support for all platform supported by compose-multiplatform.
inState
withadditionalIsInState
has been deprecated in favor of thecondition
block.inStateWithCondition
has been deprecated in favor of thecondition
block.
- Updated to Kotlin 1.8.21 and Coroutines 1.7.0.
- Added support for Kotlin/JS
- Added support for all tier 1, 2 and 3 Kotlin/Native targets
- Removed the
@FlowPreview
opt in annotation,@ExperimentalCoroutinesApi
is still required. - The sub state machine DSL methods now take
StateMachine
instead ofFlowReduxStateMachine
as parameter. This allows using different kinds of state machines together with FlowRedux which might ease migrating a state machine to FlowRedux. - A few methods which already had reified overloads are now hidden from auto complete (this change is binary compatible).
- Fixed race condition when using sub state machines that could cause a crash when an action is dispatched shortly after the sub state machine starts.
- Support optional values in the
actionMapper
of sub state machines. When the mapper returns null the action won't be forwarded which removes the need to either handle all actions in the sub state machine or introduce a no op action.
- Dependency updates
- Remove deprecated
ChangeState
and other (deprecated friends) - Add DSL marker
- Restructure, update and extend docs
New State object
Previously all the methods in the DSL had a stateSnapshot: YourStateClass
parameter, which represented the state machine's current state at the time the DSL method was called. For all non effect methods this parameter is now replaces by a state parameter that looks like this state: State<YourStateClass>
. The new State
class has a snapshot
allowing access to the same value that you received before. It also has .mutate { }
(returns the same type as the current state, usually used with copy), .override { }
(to transition to another state subclass) and .noChange { }
methods to create the ChangeState
objects. So instead of doing MutateState { ... }
you should now do state.mutate { ... }
.
This has a few advantages:
State
knows about theInputState
type so it's not possible anymore to accidentally createMutateState
instances with the wrong input type, this is now enforced by the type system, before it would have crashed at runtime- it's also not necessary anymore to specify the type parameters for mutate state, the generics are inferred
Lambdas in the DSL
We now recommend to use lambdas instead of method references in the flow redux DSL (e.g. on<ButtonClicked> { action, state -> transitionToSomeState(action, state) }
over on(::buttonClicked
/on(::transitionToSomeState)
) because:
- Parameters of the reference are required to be there but the compiler warns when they are unused, in a lambda you can just use
_
and remove the parameter from the method. - The function name should describe what it does (
doSomething
) but in practice we usually see it being named after the action (e.g.on(::buttonClicked)
). The assumption is that if you haveon<ButtonClicked> { ... }
you are less inclined to call the methodbuttonClicked
as well. - An addition to the above is that if you do
on(::doSomething)
you lose the information of when it happens whileon<ButtonClicked> { transitionToSomeState(it) }
would make getting an overview easier. Of course you can combine both in your function name but that leads to long/weird names. For exampleonButtonClickedTransitionToSomeState
is long and would then result inon(::on...)
while leaving out theon
from the method name reads weirdly when looking at just the function. - Method references don't work well when the method has a dependency. In practice the function is just put into the state machine class which means it's not testable on its own anymore. While we introduced functional interfaces in [#189].(#189) to make this easier, they are also a lot more verbose. If you just call a method from the lambda you can pass additional parameters to it and it keeps the syntax more aligned.
- In some circumstances (not sure when it happens) the IDE can't really auto complete the referenced function when you're writing
::...
Other changes
- Renamed
stateMachine
DSL method toonEnterStartStateMachine
initialStateSupplier
is now called whenever the state collection starts- The initial state in the compose integration is now
null
- Don't swallow ClassCastExceptions from the handler
- The state machine will now throw an exception when state is collecting more than once at the same time #308
ChangeState.reduce
is now public for testing purposes #309
Breaking changes:
- Removed
dsl
artifact (and gradle module).FlowReduxStateMachine
and all DSL stuff now lives insideflowredux
artifact. Change your maven coordintaes fromcom.freeletics.flowredux:dsl:0.11.0
tocom.freeletics.flowredux:flowredux:0.12.0
. Package names renamed the same so no breaking change at code level. This is just a breaking change at artifact and packaging level. - Removes Logger as we don't need it
Fixed:
- Add usage of atomic variables
- remove obsolete experimental annotations
New
- Convenience artefact to work with jetpack compose:
FlowReduxStateMachine.rememberStateAndDispatch()
val stateMachine = MyFlowReduxStateMachine()
@Composable
fun MyUi(){
val (state, dispatch) = stateMachine.rememberStateAndDispatch()
...
}
- Overload for sub-statemachine
New:
- support for composable child state machines
- Support for Apple Silicon targets
- Added a check that throws an exception if
FlowReduxStateMachine.dispatch(action)
is called before collectingFlowReduxStateMachine.state
Breaking API change:
FlatMapPolicy
is renamed toExecutionPolicy
Fix:
- fix a crash caused by resubscribing to a state machine (introduced in 0.9.0)
Breaking API changes:
FlowReduxStateMachine
is not usingStateFlow
anymore. That makes the Statemachine "cold" again.
Addition:
- Turned type alias for DSL lambdas into
fun interface
New:
- Introduced
onActionEffect
,onEnterEffect
andonCollectWhileInStateEffect
to do some work as a sort of "side effect" without changing the state - Introduced
collectWhileInState(flowBuilder: (Flow<State> -> Flow<Value>)
- Overloads for
collectWhileInstate
andon<Action>
to pass in function references without the need of specifyingFlatMapPolicy
or explicitly use named argument for handler.
A bunch of Bug fixes, please update!
Fixes:
- Cancel
onEnter
block if state is left - Cancel
onAction
block if state is left - Cancel
collectWhileInState
block if state is left - Fixed unit tests to run with multithreaded dispatcher
API changes:
- Removed FlatMapPolicy from
onEnter
- Removed
collectWhileInAnyState
. UseinState<RootClassFromStateHierarchy> { collectWhileInState(flow) {... } }
instead to get to the same endresult.
- Some internal improvements mainly around removing
Channel
and replacing it withMutableSharedFlow
This is a major change and milestone towards 1.0 release
This release contains breaking changes
ChangeState
is return type for all DSL blocks such asonEnter{ ... }
. It replacessetState{ ... }
to trigger state transitions. Furthermore, this allows us to easily write functions that can be unit tested more easy compared to how it worked before (setState
and 'getState'). A function signature i.e. to handle an action looks as follows:fun handleAction(action : MyAction, stateSnapshot : MyState) : ChangeState<State>
getState' has been removed as it's not needed anymore because
ChangeState` replaces it.inStateWithCondition
replaces `inState(condition : (State) -> Boolean)' to avoid issues with overloads and type erasure on jvm.
- Compiled with Kotlin 1.4.10 (binary compatible with Kotlin 1.4.0)
Breaking change
Artifact coordinates did change: For multiplatform are from now on
implementation 'com.freeletics.flowredux:flowredux:0.4.0'
implementation 'com.freeletics.flowredux:dsl:0.4.0'
and for jvm:
implementation 'com.freeletics.flowredux:flowredux-jvm:0.4.0'
implementation 'com.freeletics.flowredux:dsl-jvm:0.4.0'
This is more streamlined now with kotlin multiplatform library packaging best practices.
New
- Added
setState (runIf: (State) -> Boolean ) { ... }
where inrunIf
you can specify if this setState block should actually run or not. Per default it will only run if you are still in the state specified ininState
- Added a generic way to define
inState(isInState = (State) -> Boolean) { ... }
in addintion toisInState<State>
.
Breaking changes
- Renamed
observeWhileInState
tocollectWhileInState()
#63 - Renamed
observe()
tocollectInAnyState()
- Renamed type alias
StateAccessor
toGetState
Improvement
- Don't package test libraries in jvm dsl jar artifact #54
- Multiplatform release for iOS, jvm, watchOS and TvOS. JavaScript not included yet.
- Renamed
library
artifact toflowredux
- introduces
inState<> { onEnter() }
to DSL - Added a sample app for android and iOS (using SwiftUI).
First official release targeting JVM only (Multiplatform coming soon). Contains
- FlowrRedux: the core library (think of it as the low level API)
- FlowRedux-DSL: A fluend DSL to describe your ReduxStore (think of it as the high level API)l