SnapshotStateList 如何检测到发生了变化?

huangapple go评论110阅读模式
英文:

How SnapshotStateList detects that a change has occurred?

问题

假设我有一个用于学生的SnapshotStateList,并且学生的定义如下:

data class Student(val id: Int, var name: String)

val students = mutableStateListOf(Student(0, "Aaron"))

我的Jetpack Compose希望在学生列表发生变化时重新组合。

我找到了以下函数来触发它:

fun addStudent(name: String) {
    students.add(Student(students.size, "Bob"))
}
fun removeStudent(key: Int) {
    students.remove(key)
}
fun replaceStudent(key: Int, name: String) {
    val old = students[key]
    students[key] = Student(old.id, name)
}

但以下函数不能触发它:

fun modifyStudent(key: Int, name: String) {
    students[key].name = name
}

为什么?SnapshotStateList如何检测到变化发生了?

英文:

Suppose I have a SnapshotStateList for Student, and the definition of Student is:

data class Student<val id: Int, var name: String>

val students = mutableStateListOf(Student(0, "Aaron"))

My Jetpack compose in wants to recompose when students changes.

Found the following function to trigger it:

fun addStudent(name: String) {
    students.add(Student(students.size, "Bob"))
}
fun removeStudent(key: Int) {
    students.remove(key)
}
fun replaceStudent(key: Int, name: String) {
    val old = students[key]
    students[key] = Student(old.key, name)
}

But the following function cannot trigger it:

fun modifyStudent(key: Int, name: String) {
    students[key].name = name
}

Why, how does SnapshotStateList detect that a change has occurred?

答案1

得分: 1

快照系统将检测SnapshotStateList本身的更改,而不是其中可变状态的更改。

代码,

fun replaceStudent(key: Int, name: String) {
    val old = students[key]
    students[key] = Student(old.key, name)
}

会修改students,被检测为更改。

fun modifyStudent(key: Int, name: String) {
    students[key].name = name
}

修改了某些Student对象的name属性,但快照系统不会将其视为更改。

我建议您将Student设计为不可变的,而不是可变的,

data class Student(val id: Int, val name: String)

然后,replaceStudent 将需要修改学生。

或者,您可以将Student更改为,

class Student(val id: Int, name: String) {
    var name by mutableStateOf(name);
}

这将使Student可观察,并在name属性更改时通知 Compose。

我建议将Student设计为不可变的。

作为额外建议,我建议您在这种情况下使用 SnapshotStateMap 而不是 SnapshotStateList,因为如果您在删除学生后调用removeStudent,则学生的key将不匹配students中的索引。使用 SnapshotStateMap 可以解决此问题。此外,您还需要更改addStudent,不要使用 size 作为下一个 id,而应使用全局整数或全局原子(如果多线程)作为下一个 id,因为现在,创建新学生将覆盖现有学生的数据,因为它会生成重复的 key 值,如果删除了任何学生,就会导致这种情况。

英文:

The snapshot system will detect changes in SnapshotStateList itself, not in changes to mutable state within it.

The code,

fun replaceStudent(key: Int, name: String) {
    val old = students[key]
    students[key] = Student(old.key, name)
}

modifies students and is detected as a change.

fun modifyStudent(key: Int, name: String) {
    students[key].name = name
}

modifies the name property of some Student object which is not seen by the snapshot system as a change.

I recommend you make Student immutable instead of mutable,

data class Student(val id: Int, val name: String)

Then replaceStudent would be required to modify update the student.

You could, alternately, change Student to,

class Student(val id: Int, name: String) {
    var name by mutableStateOf(name);
}

which will make Student observable and notify Compose whenever the name property is changed.

I recommend making Student immutable.

As a bonus, I recommend you use SnapshotStateMap instead of SnapshotStateList in this case as if you ever call removeStudent above the key of the students after the remove will not match the index into the students. Using a SnapshotStateMap will fix this. You also need to change the addStudent to not use size as the next id but, rather, use a global integer or an global atomic (if you are multi-threaded) as, now, creating a new student will overwrite an existing student's data as it causes duplicate key values to be generated if any student was deleted.

huangapple
  • 本文由 发表于 2023年7月13日 17:59:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76678147.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定