https://kotlinlang.org logo
#compose
Title
# compose
c

colintheshots

03/21/2022, 9:55 PM
Is there a recommended way to merge two MutableStates into one emitting changes from the most recently updated?
r

Rafs

03/21/2022, 9:56 PM
m

myanmarking

03/21/2022, 9:59 PM
I dont see how derivedstate would help in this case. I know you can snapshot both then merge into a new state, but probably there is a better way
a

Alex Vanyo

03/21/2022, 11:20 PM
When you say you want to merge two
MutableStates
into one, what do you mean exactly? Do you want to compute some other state based on two input states?
m

myanmarking

03/22/2022, 12:07 AM
I guess he means flow merge behavior like.
z

Zach Klippenstein (he/him) [MOD]

03/22/2022, 3:57 PM
The fact that you’re asking a time-related question (“most recently updated”) about states is a red flag that you might be trying to do something that doesn’t make sense with what “state” really means. Conceptually, states just “are”, they don’t “emit” values at a point in time.
It sounds like you might be dealing with events, and trying to create a state that is “the most recently emitted event”. But you shouldn’t use
MutableState
to communicate about events, `Flow`s are much better suited to that.
c

colintheshots

03/22/2022, 4:04 PM
That seems a reasonable point. What I’m aiming to do is to accept updates from a sub-screen. I’m already updating a rememberSaveable mutableState of type TextFieldValue every time the user enters input into a textfield. I also need to be able to open a new composable to allow the user to craft a link and then pass it back into that textfield (inserting it into the text where the TextFieldValue shows the cursor to have been and also updating the cursor position in that TextFieldValue).
z

Zach Klippenstein (he/him) [MOD]

03/22/2022, 4:38 PM
So something like this?
Copy code
var mainText by remember { mutableStateOf(TextFieldValue("")) }
var editingLink by remember { mutableStateOf(false) }
var linkText by remember { mutableStateOf("") }

if (editingLink) {
  TextField(
    linkText,
    …,
    imeAction = {
      editingLink = false
      mainText = mainText.copy(/* insert linkText at selection position */)
    }
  )
} else {
  TextField(
    mainText,
    …,
  )
  // Some event handler that sets editingLink to true
}
c

colintheshots

03/22/2022, 8:06 PM
Oh, so you’re suggesting putting the link editing sub-screen within the same screen, but swapping out UI. This actually might work great. I was struggling with going to another screen and passing the data back and forth through Jetpack Compose Navigation routes. It seems like these aren’t intended for larger data objects, like a passage of Markdown text. Even URL-encoding the text was causing crashes because it broke parsing the route if there were encoded newlines. This solution should be far more resilient. Thank you!
z

Zach Klippenstein (he/him) [MOD]

03/23/2022, 5:45 PM
I mean, idk what you want the actual UI to look like. That was just the simplest interpretation i thought of off the top of my head based on the intent you described. If you actually want to back out to another screen, then you’ll have to hoist the state for this stuff up above your individual screens, yea.
c

colintheshots

03/23/2022, 6:57 PM
Yeah, I was dealing with a real mess of state hoisting. Simply swapping the UI in-place may be simpler here even though it adds complexity around a standard Composable which we reuse elsewhere in many places.
2 Views