Hello, I have two stores with their respective sta...
# mvikotlin
f
Hello, I have two stores with their respective state. Store A push store B. I change the state of the B and when I back to A the state is modified as well. Log is quite for store A, either dispatcher or label or action is not called. I am not understanding the reason. How could I to debug that??
a
Could you elaborate, what you mean by "Store A push store B"? If the state of a store is changed, then its reducer must be called before that change. You could put a breakpoint there and check.
f
"Store A push store B" means store A navigates to store B with push command. I already put breakpoint in reducer of Store A and is not stopped.
I also putted a log inside component of the store A.
Copy code
init {    
    store.stateFlow.onEach {
        logger.d { "$it" }
    }.launchIn(scope)
}
override val states: StateFlow<AdvancedStore.State> = store.stateFlow
Nothing is logged here when I navigates to Store B and back to store A. When the Store B is popped and Store A is active again the main composable function is recomposed with the new state of store A even with no dispatcher called, no logger is called.
Copy code
internal fun StroboAdvancedContent(component: AdvancedComponent) {
    val state by component.states.collectAsState()
    // here the state has the new state
}
a
Can you show the code of the component
states
property?
f
Just out of curiosity, the structure of store A and store B is very similar.
a
State of a store can't be changed without calling the reducer. There must be something else affecting the component's
states
property.
f
Copy code
interface AdvancedComponent {
    val states: StateFlow<AdvancedStore.State>
}
Copy code
internal class AdvancedComponentImpl(
    private val componentContext: ComponentContext,
    private val storeFactory: StoreFactory,
    private val strobo: StroboRepository,
    private val output: (Output) -> Unit,
    private val channel: Int,
) : AdvancedComponent, ComponentContext by componentContext {

    private val store =
        instanceKeeper.getStore {
            AdvancedStoreImpl(
                storeFactory = storeFactory,
                stroboRepository = strobo,
                channel = channel,
            ).create()
        }

    @ExperimentalCoroutinesApi
    override val states: StateFlow<AdvancedStore.State> = store.stateFlow

}
===============================
Copy code
interface AdvancedEffectsComponent {
    val states: StateFlow<AdvancedEffectsStore.State>
}

internal class AdvancedEffectsComponentImpl(
    private val componentContext: ComponentContext,
    private val storeFactory: StoreFactory,
    private val strobo: StroboRepository,
    private val output: (AdvancedEffectsComponent.Output) -> Unit,
    private val channel: Int,
    private val indexEffect: Int,
) : AdvancedEffectsComponent, ComponentContext by componentContext {

    private val store =
        instanceKeeper.getStore {
            AdvancedEffectsStoreImpl(
                storeFactory = storeFactory,
                stroboRepository = strobo,
                channel = channel,
                indexEffect = indexEffect,
            ).create()
        }

    @ExperimentalCoroutinesApi
    override val states: StateFlow<AdvancedEffectsStore.State> = store.stateFlow

}
a
This all looks fine.
The state can't be taken from nowhere. If you believe it gets changed, then somewhere it must be instantiated. You can add an init section with dummy code in your state class, and put breakpoint there.
By "recomposed with new state" do you mean that there is new state not equal to the previous one? Or the function is recomposed with the old state?
I assume the latter, because you are saying that the new state is not emitted when you observe in your component. So perhaps the Composable function is being recomposed with the old state, which is fine.
f
"recomposed with new state" means that new state is not equal to the previous one. I will summarize the steps here : • Store A (AdvancedStore) fetch data from repository and displaying on the screen. Store A has a property called colorPrimary and others. Store A navigates (push) for Store B. • Store B (AdvancedEffectsStore) also fetch data from repository and displaying on the screen. Store B also has a property called colorPrimary and others. Store B updates colorPrimary property in repository. • Store B is popped of the stack navigation. The screen of the StoreA must be recomposed with old state once its dispatcher is not called, but the screen is recomposed with the new value updated in Store B (primaryColor). There is not interaction with Store A when Store B is active. Seems that the Store B is updating the state of the Store A. But, how????? I am looking for the reason.
@Arkadii Ivanov I made a simple sample with the issue https://github.com/francismariano/testmvikotlin
when you can please take a look
a
A new state cannot be created without calling the reducer. If you believe that a new instance of state is created, then try placing a breakpoint in state's
init
section to see where it gets created. I'm on vacation currently, not sure when I'll be able to check. Sorry.
f
I did not know you was on vacation. My apologizes and enjoy!!!!
a
Thanks!
f
@Arkadii Ivanov when you have a time, please see the demo project with the issue discussed previously. Thank you so much
a
Sure. Could you provide steps to reproduce?
And also please describe the actual behaviour and the expected.
I have checked quickly. When I click on "Update color 1" and then without changing anything just press back, then the previous screen is recomposed once with the same state as before. When I click on "Update color 1", then click on different color, then click back, then the previous screen is recomposed once with the updated state. This works as expected.
f
Hello. You are right. I do not know the reason, but I saw a weird behaviour when I tested some time ago. My apologize. Other thing, today I see that was doing wrong when update a store with list or map property. The correct is copy the current list/map for new one. I was just assigning the same object.