繁体   English   中英

在 Composable 中获取 state 的先前值 - Jetpack Compose

[英]Get previous value of state in Composable - Jetpack Compose

假设我的代码看起来像这样

@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 的东西

我发现我可以通过使用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
    }
}

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

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

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

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 function,但我发现remember在我的情况下不起作用,因为即使没有传入任何keys ,它也总是重新渲染。

用法:


@Composable
fun SomeComponent() {

    ...
    val prevValue = rememberPrevious(currentValue)
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM