在Compose中管理网络请求竟然如此简单!
写在前面
本文中提及的 use
开头的函数,都出自与我的 ComposeHooks 项目,它提供了一系列 React Hooks 风格的状态封装函数,可以帮你更好的使用 Compose,无需关心复杂的状态管理,专心于业务与UI组件。
这是系列文章的第7篇,前文:
- 在Compose中使用useRequest轻松管理网络请求
- 在Compose中使用状态提升?我提升个P…Provider
- 在Compose中父组件如何调用子组件的函数?
- 在Compose中方便的使用MVI思想?试试useReducer!
- 在Compose中像使用redux一样轻松管理全局状态
- 在Compose中轻松使用异步dispatch管理全局状态
在上篇文章中我提到如果你项目中使用的是retrofit,并且已经做了协程改造,那么你可以轻松的将你的网络请求改造到 Compose 中,使用状态驱动你的UI。
上一个例子比较粗糙,可能有小伙伴不理解,同时考虑到减少模板代码,我升级了 useRedux 系列钩子,下面我将演示如何在项目中轻松的使用网络请求,并且不用再担心重组导致请求状态消失!amazing!!!!
Compose 下网络请求的痛点
众所周知,Compose的组件是有状态驱动的,并且作为函数式组件,它会不断地重组。
当我们的组件不可见时,状态从状态树移除,如果想要保留状态就需要使用 ViewModel 来进行一些状态保存,但是 viewModel 本身也会因为跨页面导航丢失状态,每次再进入页面都要重新发起请求,不能保存之前的请求状态无疑是非常制杖的!
那么怎么才能丝滑的使用网络请求呢?如何避免网络请求因为重组再次发起?
答案就是上两篇文章,我们通过 ReduxProvider 将状态提升到最根部,那么全局范围内,同一个网络请求在全局使用相同的状态,就不会出现各种场景下的状态丢失了。
show time !!
1. 创建状态存储 store
1 | // 请求的状态封装 |
上篇文章介绍了,在 createStore
函数的闭包作用域内,你可以使用中缀函数 with
,来创建一条存储,并且将 reducer
函数与初始状态传递给store;
同样的你可以使用 named(alias){}
这个作用域函数,来创建一个带别名的状态存储,这里的 fetch1
、fetch2
是请求状态的别名,你应该使用有实际意义的名称。
所有的网络请求都是相同的逻辑,所以我们可以直接使用 forEach 来批量创建具有别名的状态存储;
2. 通过 ReduxProvider
暴露状态存储
1 | class MainActivity : ComponentActivity() { |
将 ReduxProvider
置于根组件,全局共享状态
3. 按需使用
1 |
|
useSelector<NetFetchResult>("fetch1")
即可拿到对应别名的状态,useDispatchAsync<NetFetchResult>("fetch1")
则可以拿到对应的 异步 dispatch
函数;
现在你无需对你过去的网络请求做任何改动,不需要 ViewModel,不需要LaunchedEffect,直接在 dispatchAsync 中使用 retrofit 发起请求!
1 | dispatchAsync { it-> |
这里的 it
是 dispatch 函数,你可以在闭包内发起状态变更,对你的网络请求进行 try-catch
,然后将结果或者异常使用 NetFetchResult.Success
或 NetFetchResult.Error
包装即可!
最后请说声:⌈ 多谢提升哥!⌋
状态管理三剑客
到此为止我们已经介绍了三位用于在 Compose 中进行状态管理的钩子函数:
useReducer
:用于实践MVI,只需要传递 reducer 函数与初始状态,返回给我们状态、dispatch函数useContext
:用于状态提升,解耦组件之间的状态传递,底层实现是:ProvidableCompositionLocal
与CompositionLocalProvider
useSelector
/useDispatch
:基于useContext
实现的的全局版本的useReducer
探索更多
好了以上就是 hooks 1.0.10 版本带来的一点小小改动,现在你可以自信在在Compose中使用网络请求了!
项目开源地址:junerver/ComposeHooks
MavenCentral:hooks
1 | implementation("xyz.junerver.compose:hooks:1.0.10") |
欢迎使用、勘误、pr、star。