簡體   English   中英

Jetpack compose mutableStateOf 列表在更改列表項中的屬性值時不會觸發重新組合 class

[英]Jetpack compose mutableStateOf list doesn't trigger re-composition when changing property value in list item class

我想我在這里遺漏了 Jetpack Compose 的核心概念。 當我嘗試更改可組合項內的non-constructor data class property時遇到問題,而此可組合項是觀察列表的一部分。

不起作用:(構造函數中未聲明sadProperty

data class IntWrapper(val actualInt: Int = 0) {
var sadProperty: Int = 0
}

@Preview
@Composable
fun test() {
var state by remember { mutableStateOf(listOf(IntWrapper(1), IntWrapper(2), IntWrapper(3),IntWrapper(4)))}

    fun onClick(item: IntWrapper) {
        val indexOf = state.indexOf(item)
        val newState = state.minus(item).toMutableList()
        val copy = item.copy()
        copy.sadProperty = Random.nextInt()
        newState.add(indexOf, copy)
        state = newState
    }
    
    Column() {
        for (item in state) {
            Text("ac: ${item.actualInt} sad: ${item.sadProperty}", modifier = Modifier.clickable { onClick(item)})
        }
    }

}

作品:( actualInt在構造函數中聲明)

data class IntWrapper(var actualInt: Int = 0) {
var sadProperty: Int = 0
}

@Preview
@Composable
fun test() {
var state by remember { mutableStateOf(listOf(IntWrapper(1), IntWrapper(2), IntWrapper(3),IntWrapper(4)))}

    fun onClick(item: IntWrapper) {
        val indexOf = state.indexOf(item)
        val newState = state.minus(item).toMutableList()
        val copy = item.copy()
        copy.actualInt = Random.nextInt()
        newState.add(indexOf, copy)
        state = newState
    }
    
    Column() {
        for (item in state) {
            Text("ac: ${item.actualInt} sad: ${item.sadProperty}", modifier = Modifier.clickable { onClick(item)})
        }
    }

}

有人可以解釋為什么會這樣嗎?

這看起來像是Jetpack Compose和關於Kotlin數據 class 的問題,請告訴我,我會盡力而為。

讓我們先從 Kotlin 的數據類開始

根據kotlin關於Data Class的文檔

編譯器自動從主構造函數中聲明的所有屬性派生以下成員:

  • equals()/hashCode() 對
  • 形式為“User(name=John, age=42)”的 toString()
  • componentN() 函數對應於聲明順序中的屬性。
  • 復制()。

您的IntWrapper數據 class 有一個Primary Constructor , class 名稱后面的括號,以及其中聲明的 1 個屬性。

data class IntWrapper(val actualInt: Int = 0) {
      var sadProperty: Int = 0
}

這樣,我們可以說,您的IntWrapper數據 class 有

  • 1 個組件 ( actualInt )
  • 形式IntWrapper(actualInt=?)
  • 生成的copy() function
  • 生成的 equals()/hashCode() 對

並再次基於文檔

編譯器僅使用主構造函數中定義的屬性來自動生成函數。 要從生成的實現中排除屬性,請在 class 正文中聲明它:

equals將僅使用/評估從IntWrapper's主要構造函數(即actualInt: Int )聲明的屬性,而sadProperty被排除在外,因為它位於數據 class 主體的一部分。

現在考慮以下問題:

val intWrapper1 = IntWrapper(actualInt = 5)
intWrapper1.sadProperty = 5

val intWrapper2 = IntWrapper(actualInt = 5)
intWrapper2.sadProperty = 10

Log.e("AreTheyEqual?", "${intWrapper1 == intWrapper2}")

它打印,

E/AreTheyEqual?: true

因為equality認為兩個派生屬性具有相同的值5sadProperty被排除在這個比較之外。

val intWrapper1 = IntWrapper(actualInt = 5)
intWrapper1.sadProperty = 5

val intWrapper2 = IntWrapper(actualInt = 10)
intWrapper2.sadProperty = 5

印刷,

E/AreTheyEqual?: false

因為生成的 equals 驗證生成的組件( actualInt )與兩個IntWrapper實例不同。

現在轉到Jetpack Compose ,應用我們對數據類的理解,

  • 第一個test符合data class的所有內容,它創建了一個具有新值的新 object ,這就是Compose觸發re-composition所需要的。

  • 第二個test不會觸發re-compositionCompose仍然看到相同的IntWrapper實例,因為sadProperty不是將由數據類的 equals 操作使用的生成組件的一部分。

在 Compose 中,您必須使用以下兩種方法之一才能成功執行重組操作:

1 - 使用 mutableStateListOf(),但是,通過更新列表中項目的值,執行重組操作

2- 使用您發布的自己的方法

但是對於第二種方法,你需要告訴Compose,actualInt發生了變化,所以你需要創建一個新的int實例。

如果你不想這樣做,你需要更多地解釋你的場景,以便我提供更完整的指南

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM