Hi, I am new to Compose and I'm having some doubts...
# compose-desktop
j
Hi, I am new to Compose and I'm having some doubts about state management. I have an
AppState
object and it has some values in nested properties that I want to access. If I use
mutableStateOf()
, the state only updates when the entire
AppState
object is changed not when its properties change. I have also tried kotllin Flow for the first time but the only solution I could get was to make each of the properties a flow and then individually watch them in the main compose function. Is there any other way to manage state where I need to watch nested properties?
a
You can use
mutableStateOf()
at property level. Something similar to this.
j
Is
structuralEqualityPolicy()
the thing that helps deal with the nested properties?
a
No. That has nothing to do with whether it is a property or not. Read the doc for what it is used for.
j
I looked at the link you sent but i couldn't find anything different from what was doing. Adding the equality policy didn't make any difference cause that is the default value already.
Copy code
class AppState {
    var fileState = mutableStateOf(File(""))
    var coreState = mutableStateOf(emptyCore())

    private fun createCore() {
        val (instructions: List<Instruction>, parsedVariableData: List<ParsedData>) = Parser.parseDataFromFile(fileState.value)
        val program = Program(
            instructions = instructions,
            parsedData = parsedVariableData
        )
        coreState.value = Core(program = program)
    }

    val loadFile: (File) -> Unit = {
        fileState.value = it
        createCore()
    }

    val executeProgram: () -> Unit = coreState.value::runProgram
}
This is my state file, when I update the file, the UI related to the file updates but the ones that related to the core do not. I don't get why that's happening.
a
You can do something like this:
Copy code
class AppState {
    var file by mutableStateOf(File(""))
    val core by derivedStateOf {
        val (instructions: List<Instruction>, parsedVariableData: List<ParsedData>) = Parser.parseDataFromFile(file)
        val program = Program(
            instructions = instructions,
            parsedData = parsedVariableData
        )
        Core(program = program)
    }
}
And if you meant that
executeProgram
is not updating, it's expected because you are not updating it.
j
runProgram
updates it's internal state. If I use
derivedStateOf
then it won't be able to reflect that change.
Cause as far as I understand,
derivedStateOf
will evaluate the block that I pass to it when I call
core.value
so it'll create a new core every-time something changes.
a
What is
runProgram
? And you don't want
core
to be updated every time
file
changes? Can you describe what you want more specifically?
j
I am trying to create an ARM simulator. I load a program (with some instructions) into the core and when i run it the properties of the core like the
memoryArray
and
registerArray
will get updated ( will have new values after running instructions like ADD, SUB etc.). The instructions come from the file, so when I load a new file I have to parse it and for now it creates a new core. So when
file
changes I need a new core, but after
runProgram
I need the same core but its property values will be different.
a
So when 
file
 changes I need a new core
The code I posted above does exactly this. If you want the properties of
Core
to be observable, just define them as states (e.g.
var memoryArray by mutableStateOf(emptyArray())
).
j
So I have to do this for all the properties?
registerArray
has some values that I need to observe that are nested in some more objects. I already thought of doing this but doing it individually for all of them is repetitive and fragile so I was trying to find a better approach.
a
I don't think
var memoryArray by mutableStateOf(emptyArray())
and
var memoryArray = emptyArray()
differ much in terms of verbosity. You can't expect properties to automatically become observable.
j
I am trying to keep the UI logic and the application logic separate in different modules so if you meant I have to place the
memoryArray by mutableStateOf
where
Core
or
MemoryArray
is defined I can't do that
a
What make you think
mutableStateOf()
is UI logic?
j
It's specific to Compose right
If later I want to make the UI using Tornado FX I'll have to change that
a
Then you have to use
StateFlow
. Anyway you need an observable mechanism as
You can't expect properties to automatically become observable.
j
For now I'll just go with what you said making each of them properties a
mutableStateOf
but I'll try to make them properties in
AppState
by individually referencing them from the
core
variable.
Yeah or I'll try with Flows again.
Thanks 👍
👍 1
c
I had this problem too at first where using mutableStateOf felt wrong because it felt like I was strongly tying myself to compose. Now I just use it instead of trying to use flows or anything and everything is easy and it just works. /shruggie
m
I also found it helpful to use persistent data structures to represent more complex state. This way the
mutableStateOf
always changes when any of the nested properties is changed.