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

Colton Idle

01/15/2021, 10:15 PM
Typing into a text field in a lazy column is laggy (even in the state codelab where it does this) Is that an issue or is there something we can do to fix this?
a

Alex Petitjean

01/15/2021, 10:20 PM
If you're on Linux with multiple monitors, it could be related to this issue: https://github.com/JetBrains/compose-jb/issues/23 If not then I have no idea blob shrug
c

Colton Idle

01/15/2021, 10:20 PM
Not desktop. Compose on android.
s

Siyamed

01/15/2021, 10:26 PM
Responded on the ticket, not sure it was you who created the ticket @Colton Idle
c

Colton Idle

01/15/2021, 10:44 PM
Wasn't me but thanks! @Siyamed so the solution is to have an extra piece of state?
s

Siyamed

01/15/2021, 10:47 PM
That is what it looks like
Solution not in the sense of workaround but what it should be
c

Colton Idle

01/15/2021, 10:51 PM
Hm. That is odd to me because it goes against the whole single source of truth? But what do I know. I've been doing Compose for like 6 hours tops. Lol
s

Siyamed

01/15/2021, 10:52 PM
you can one state for the whole app :) that would be single source of truth as well :)
I currently cant speak for the the specific code, but in general each of the TextFields should have their iwn state
I believe there is something wrong with the codelab
The recreation of the list was suspicious
j

jim

01/16/2021, 12:22 AM
Errr, I think @Colton Idle is right, unless I'm miss-reading this, comment #3 in the issue seems like a huge antipattern and is very much not the right solution.
I agree with @Siyamed though that the
todoItems.toMutableList().also {
looks very suspicious and probably that codelab needs some additional review.
s

Siyamed

01/16/2021, 12:27 AM
me reading the code as “each TextField has their own state” caused me to mislead. I strikethrough’ed it 🙂
@jim having a listOf<MutableState> instead of mutableStateOf<List> is not an antipattern is it correct?
j

jim

01/16/2021, 12:31 AM
listOf<MutableState>
is probably wrong, the user probably wanted
mutableStateListOf
instead.
mutableStateOf<List>
could be ok in some circumstances, but it has a very different behavior from
mutableStateListOf
👍 1
s

Siyamed

01/16/2021, 12:35 AM
One question :)
MutableStateListOf is a mutable list right? So it would work well when we want to add and remove items
👌 1
Is it a good thing for a list of textfields that has their own independent state?
I was wondering the drawbacks of - create an array of 10 for 10 person names - each array element is data for a textfield - create lazycolumn for those
I would initially write this with an array of mutable states
I was wondering if that is wrong
j

jim

01/16/2021, 12:48 AM
I'm not sure I understand the questions. If there are ten people and I want to use mutable objects, I'd probably have something like a
mutableStateListOf<Person>
with each person defined as:
Copy code
class Person {
   var name by mutableStateOf<String>()
}
👍 1
If you could post a code snippet of the pattern you're imagining, maybe I can better comment on it. But as a general rule of thumb, probably mutableState should only be used as a property delegate backing a field or in a remember block. I'm not 100% confident enough to say that's a hard-and-fast rule yet (would love to see counterexamples) but that seems to be true off the top of my head without having thought too deeply about it.
s

Siyamed

01/16/2021, 12:51 AM
The person example was good
Thank you
c

Colton Idle

01/16/2021, 1:52 AM
So it seems like that codelab will need to be updated? @jim glad I was thinking correctly about the anti pattern in the comment of having multiple pieces of state. In your person example above... Is the person able to back a text field properly? So basically as long as I have mutableStateListOf<Person> in my ViewModel and class Person { var name by mutableStateOf<String>() } Then I would just pass person.name to the text field? And everything should work right? Sorry on mobile or else I'd try but I'm really curious in making sure I understand this correctly. I have a use case of building a dynamic form (think a Google form) and so I want to use a LazyColumn (for best perf) and so I want to make sure I only have a single piece of state.
j

jim

01/16/2021, 3:42 AM
Copy code
LazyColumn(...) { index, person ->
    TextField(value=person.value, onChange={person.name = it})
}
c

Colton Idle

01/17/2021, 7:07 PM
@jim was able to get to a desktop and verify that edit texts in a lazy work fine. Thanks @jim no duplication of state either!
Copy code
class MainActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        val listOfPeeps = mutableStateListOf<Person>()

        listOfPeeps.add(Person())
        listOfPeeps.add(Person())
        listOfPeeps.add(Person())

        setContent {
            ComposeTextFieldTheme {
                Surface(color = MaterialTheme.colors.background) {
                    LazyColumn(content = {
                        item {
                            Button(onClick = { listOfPeeps.add(Person()) }) {
                                Text(text = "Add person to list")
                            }
                        }
                        items(listOfPeeps) { person: Person ->
                            TextField(value = person.name, onValueChange = { person.name = it })
                        }
                    })
                }
            }
        }
    }
}

class Person {
    var name by mutableStateOf<String>("")
}
If you're still watching this thread, one thing I'm still not 100% sure about is why I need
Copy code
var name by mutableStateOf<String>("")
Couldn't I just have a var name = "" since the list is
mutableStateListOf
?
j

jim

01/17/2021, 7:09 PM
The
mutableStateList
only notifies observers when the LIST changes, not when an item within the list is mutated. If you want to be notified when the item within the list changes, that item must be observable (via state).
c

Colton Idle

01/17/2021, 7:13 PM
gotcha. makes sense. still learning, but yeah. this was pretty simple in the end to get working as intended.
unfortunately the codelab threw me off.
j

jim

01/17/2021, 7:15 PM
If the codelab threw you off, please file a bug with the section that threw you off and suggested updates to make it less misleading.
c

Colton Idle

01/17/2021, 7:18 PM
@Siyamed linked to someone else that also had codelab trouble. I'll star it though. 😁
@jim "The 
mutableStateList
 only notifies observers when the LIST changes, not when an item within the list is mutated.  If you want to be notified when the item within the list changes, that item must be observable (via state)." So something that is messing with me here is that I've been really hammering home the point that everything should be immutable if it can be. Especially in a kotlin data class like Person. Doing mutableStateOf<String> "feels" wrong. Is my person still following the "rule" of favoring immutablilty when possible?
j

jim

01/18/2021, 10:31 PM
You could make your person be a:
Copy code
data class Person(val name: String)
And just re-create the person if the name changes. That would be immutable.
You could also have a
mutableStateListOf<String>()
, as String is immutable so you don't need to wrap it in a
mutableStateOf
and can just remove and add strings as needed (although that gives you less room to grow in the future).
But no, if you are using any sort of
mutableState
then you are not favoring immutability.
c

Colton Idle

01/18/2021, 10:38 PM
Interesting. Still learning and I'm not sure this makes 100% sense yet, but I think it's clicking. Really the thing I'm trying to wrap my head around is if I needed a list of 10000 TextFields, how I would model that. Arguing with myself if
Copy code
data class Person(val name: String)
is better, or
Copy code
class Person {
   var name by mutableStateOf<String>()
}
j

jim

01/18/2021, 10:40 PM
Which one is better probably depends more on the rest of your app and data model, than a hard and fast rule. But the rule of thumb is to favor immutability, so maybe I'd go with the first one? Or maybe it's a coin toss.
c

Colton Idle

01/18/2021, 10:46 PM
@jim aha. Okay. I didn't know the first option was still "okay". I thought I "had" to use the second option in order for a list of TextFields to work. I will have to try this in a sample that isn't the Compose State codelab. I updated the codelab to use the mutableStateListOf and I was still seeing laggy typing, and so I thought the codelab was completely wrong since it didn't use
var name by mutableStateOf<String>()
2 Views