【问题标题】:Get previous value of state in Composable - Jetpack Compose在 Composable 中获取先前的状态值 - Jetpack Compose
【发布时间】:2022-01-03 02:10:13
【问题描述】:

假设我的代码如下所示

@Composable
fun ExampleList() {
    val tickers by exampleViewModel.tickers.observeAsState()
    LazyColumn() {
        items(items = tickers) { ticker ->
            ExampleItem(ticker)
        }
    }
}
@Composable
fun ExampleItem(ticker: Ticker) {
    Text(text= ticker.lastPrice)
}

每次更新代码时,是否可以在 ExampleItem Compose 中获取代码的先前值?
我想知道 React Native 中是否有类似 componentDidUpdate 的东西

【问题讨论】:

    标签: android android-jetpack android-jetpack-compose


    【解决方案1】:

    我发现我可以使用remember {mutableStateOf} 来获取ticker 的最后一个值,如下所示:

    var lastTicker by remember { mutableStateOf(ticker)}
    
    SideEffect {
       if (lastTicker != ticker) {
         // compare lastTicker to current ticker before assign new value
       
         lastTicker = ticker
       }
    }
    

    通过使用remember { mutableStateOf(ticker)},我可以通过重组保持股票代码的价值。

    然后在 SideEffect 中,我可以使用 lastTicker 值(在我的情况下比较最后一个代码和当前代码),然后将其分配给新值以用于下一个组合

    或使用derivedStateOf 仅观看代码变化,避免重新组合

    val compareValue by remember(ticker) {
        derivedStateOf {
            // compare lastTicker to current ticker before assign new value
    
            lastTicker = ticker
           // return value
        }
    }
    

    【讨论】:

    • 我很确定 remember(ticker) 只有在 ticker 发生变化时才会计算(这就是键的全部概念)。所以这里的derivedStateOf 在功能上什么都不做
    【解决方案2】:

    虽然答案在技术上是正确的,但第一个示例渲染次数过多,不幸的是我没有理解第二个示例。

    所以我回到React 看看它是如何在那里完成的,并且解释得很好here

    这就是钩子(remember 函数)的样子(对于好奇的人):

    function usePrevious<T>(value: T): T {
      // The ref object is a generic container whose current property is mutable ...
      // ... and can hold any value, similar to an instance property on a class
      const ref: any = useRef<T>();
      // Store current value in ref
      useEffect(() => {
        ref.current = value;
      }, [value]); // Only re-run if value changes
      // Return previous value (happens before update in useEffect above)
      return ref.current;
    }
    

    同样的想法可以在 compose 中以可重用的方式实现(重要的是,在设置先前的值时不应重新渲染 @Composable):

    /**
     * Returns a dummy MutableState that does not cause render when setting it
     */
    @Composable
    fun <T> rememberRef(): MutableState<T?> {
        // for some reason it always recreated the value with vararg keys,
        // leaving out the keys as a parameter for remember for now
        return remember() {
            object: MutableState<T?> {
                override var value: T? = null
    
                override fun component1(): T? = value
    
                override fun component2(): (T?) -> Unit = { value = it }
            }
        }
    }
    

    和实际的rememberPrevious:

    @Composable
    fun <T> rememberPrevious(
        current: T,
        shouldUpdate: (prev: T?, curr: T) -> Boolean = { a: T?, b: T -> a != b },
    ): T? {
        val ref = rememberRef<T>()
    
        // launched after render, so the current render will have the old value anyway
        SideEffect {
            if (shouldUpdate(ref.value, current)) {
                ref.value = current
            }
        }
    
        return ref.value
    }
    

    key 值可以添加到remember 函数中,但我发现remember 在我的情况下不起作用,因为即使没有传入keys,它也总是会重新渲染。

    用法:

    
    @Composable
    fun SomeComponent() {
    
        ...
        val prevValue = rememberPrevious(currentValue)
    }
    
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-22
      • 1970-01-01
      • 2022-12-08
      • 2021-08-03
      • 2019-09-30
      • 2022-09-25
      相关资源
      最近更新 更多