kotlin - 如何在 kotlin-react useEffect 中订阅 StateFlow
问题描述
我正在尝试为 kotlin-react with functionalComponent
kotlin创建一个小的反例1.4-M2
。该示例应使用kotlinx.coroutines.flow
. 我正在努力从商店的反应useEffect
钩子中收集价值。
店铺:
object CounterModel { // Modified sample from kotlin StateFlow doc
private val _counter = MutableStateFlow(0) // private mutable state flow
val counter: StateFlow<Int> get() = _counter // publicly exposed as read-only state flow
fun inc() { _counter.value++ }
}
零件:
val counter = functionalComponent<RProps> {
val (counterState, setCounter) = useState(CounterModel.counter.value)
useEffect(listOf()) {
// This does not work
GlobalScope.launch { CounterModel.counter.collect { setCounter(it) } }
}
div {
h1 {
+"Counter: $counterState"
}
button {
attrs.onClickFunction = { CounterModel.inc() }
}
}
}
当我直接调用CounterModel.counter.collect { setCounter(it) }
它时抱怨Suspend function 'collect' should be called only from a coroutine or another suspend function
.
你将如何实现这个useEffect
钩子?
一旦订阅生效,您将如何取消订阅(使用useEffectWithCleanup
而不是useEffect
)?
解决方案
终于找到了解决办法。我们可以使用onEach
对每个新值执行操作,然后使用 '订阅' launchIn
。这将返回一个可以取消以进行清理的作业:
object CounterStore {
private val _counter = MutableStateFlow(0)
val counter: StateFlow<Int> get() = _counter
fun inc() { _counter.value++ }
}
val welcome = functionalComponent<RProps> {
val (counter, setCounter) = useState(CounterStore.counter.value)
useEffectWithCleanup(listOf()) {
val job = CounterStore.counter.onEach { setCounter(it) }.launchIn(GlobalScope)
return@useEffectWithCleanup { job.cancel() }
}
div {
+"Counter: $counter"
}
button {
attrs.onClickFunction = { CounterStore.inc() }
+"Increment"
}
}
我们可以将此 StateFlow 逻辑提取到自定义反应钩子中:
fun <T> useStateFlow(flow: StateFlow<T>): T {
val (state, setState) = useState(flow.value)
useEffectWithCleanup(listOf()) {
val job = flow.onEach { setState(it) }.launchIn(GlobalScope)
return@useEffectWithCleanup { job.cancel() }
}
return state
}
并在我们的组件中像这样使用它:
val counter = useStateFlow(CounterStore.counter)
完整的项目可以在这里找到。Flow-Api 是非常实验性的,所以这可能不是最终的解决方案 :)
推荐阅读
- powerbi - Power BI 前 N 个底部的结果太多
- python - 如何使用坐标数据从矩阵中找到最大的元素?
- python - Pandas:按索引在多索引数据帧之上添加单个索引数据帧
- javascript - 保持函数的变量和函数本身的区别
- c# - 列表
与列表 ,哪个会更快? - javascript - 修改vue组件方法
- excel - 如何计算在 Excel 中匹配或超过值所需的天数
- ios - 居中(直接在中心)帧中的图像
- python - Python 3.7 & 3.8 和 VSCode
- python-3.x - 如何配置 Cookiecutter Django 以使用 Gmail SMTP