在Jetpak Compose中管理网络请求竟然如此简单!

写在前面

本文中提及的use开头的函数,都出自与我的 ComposeHooks 项目,它提供了一系列 React Hooks 风格的状态封装函数,可以帮你更好的使用 Compose,无需关系复杂的状态管理,专心于业务与UI组件。

这是系列文章的第7篇,前文:

在上篇文章中我提到如果你项目中使用的是retrofit,并且已经做了协程改造,那么你可以轻松的将你的网络请求改造到 Compose 中,使用状态驱动你的UI。

上一个例子比较粗糙,可能有小伙伴不理解,同时考虑到减少模板代码,我升级了 useRedux 系列钩子,下面我将演示如何在项目中轻松的使用网络请求,并且不用再担心重组导致请求状态消失!amazing!!!!

Compose 下网络请求的痛点

众所周知,Compose的组件是有状态驱动的,并且作为函数式组件,它会不断地重组。

当我们的组件不可见时,状态从状态树移除,如果想要保留状态就需要使用 ViewModel 来进行一些状态保存,但是 viewModel 本身也会因为跨页面导航丢失状态,每次再进入页面都要重新发起请求,不能保存之前的请求状态无疑是非常制杖的!

那么怎么才能丝滑的使用网络请求呢?如何避免网络请求因为重组再次发起?

答案就是上两篇文章,我们通过 ReduxProvider 将状态提升到最根部,那么全局范围内,同一个网络请求在全局使用相同的状态,就不会出现各种场景下的状态丢失了。

show time !!

1. 创建状态存储 store

// 请求的状态封装
sealed interface NetFetchResult {
    data class Success<T>(val data: T, val code: Int) : NetFetchResult
    data class Error(val msg: Throwable) : NetFetchResult
    data object Idle : NetFetchResult
    data object Loading : NetFetchResult
}

// reducer
val fetchReducer: Reducer<NetFetchResult, NetFetchResult> = { _, action ->
    action
}

// 创建存储对象
val store = createStore {
    arrayOf("fetch1","fetch2").forEach {
        named(it) {
            fetchReducer with NetFetchResult.Idle
        }
    }
}

上篇文章介绍了,在createStore函数的闭包作用域内,你可以使用中缀函数 with,来创建一条存储,并且将 reducer 函数与初始状态传递给store;

同样的你可以使用 named(alias){} 这个作用域函数,来创建一个带别名的状态存储,这里的fetch1fetch2是请求状态的别名,你应该使用有实际意义的名称。

所有的网络请求都是相同的逻辑,所以我们可以直接使用 forEach 来批量创建具有别名的状态存储;

2. 通过 ReduxProvider 暴露状态存储

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            ComposeHooksTheme {
                // provide store for all components
                ReduxProvider(store = store) {
                    Surface(
                        modifier = Modifier.fillMaxSize(),
                        color = MaterialTheme.colorScheme.background
                    ) {
                        useRoutes(routes = routes)
                    }
                }
            }
        }
    }
}

ReduxProvider 置于根组件,全局共享状态

3. 按需使用

@Composable
fun UseReduxFetch() {
    val fetchResult: NetFetchResult = useSelector("fetch1")
    val dispatchAsync = useDispatchAsync<NetFetchResult>("fetch1")
    Column {
        Text(text = "result: $fetchResult")
        TButton(text = "fetch") {
            dispatchAsync {
                it(NetFetchResult.Loading)
                delay(2.seconds)
                //网络请求结果
                NetFetchResult.Success("success", 200)
            }
        }
    }
}

@Composable
fun UseReduxFetch2() {
    val fetchResult: NetFetchResult = useSelector("fetch2")
    val dispatchAsync = useDispatchAsync<NetFetchResult>("fetch2")
    Column {
        Text(text = "result: $fetchResult")
        when(fetchResult) {
            is NetFetchResult.Success<*> -> {
                // 对成功结果进行转型
                val succ= fetchResult as NetFetchResult.Success<SimpleData>
                Text(text = succ.toString())
            }
            else->{}
        }
        TButton(text = "fetch2") {
            dispatchAsync {
                it(NetFetchResult.Loading)
                delay(2.seconds)
                //网络请求结果
                NetFetchResult.Success(SimpleData("Tony Stark", 53), 200)
            }
        }
    }
}

useSelector<NetFetchResult>("fetch1") 即可拿到对应别名的状态,useDispatchAsync<NetFetchResult>("fetch1") 则可以拿到对应的 异步dispatch函数;

现在你无需对你过去的网络请求做任何改动,不需要 ViewModel,不需要LaunchedEffect,直接在 dispatchAsync 中使用 retrofit 发起请求!

dispatchAsync { it->
   it(NetFetchResult.Loading)
   delay(2.seconds) //假装在进行携程上的耗时操作
   NetFetchResult.Success(SimpleData("Tony Stark", 53), 200)
}

这里的 it 是 dispatch 函数,你可以在闭包内发起状态变更,对你的网络请求进行 try-catch,然后将结果或者异常使用 NetFetchResult.SuccessNetFetchResult.Error 包装即可!

最后请说声:⌈ 多谢提升哥!⌋

状态管理三剑客

到此为止我们已经介绍了三位用于在 Compose 中进行状态管理的钩子函数:

  • useReducer:用于实践MVI,只需要传递 reducer 函数与初始状态,返回给我们状态、dispatch函数
  • useContext:用于状态提升,解耦组件之间的状态传递,底层实现是:ProvidableCompositionLocalCompositionLocalProvider
  • useSelector/useDispatch:基于 useContext 实现的的全局版本的 useReducer

探索更多

好了以上就是 hooks 1.0.10 版本带来的一点小小改动,现在你可以自信在在Compose中使用网络请求了!

项目开源地址:junerver/ComposeHooks

MavenCentral:hooks

implementation("xyz.junerver.compose:hooks:1.0.10")

欢迎使用、勘误、pr、star。

  • 38
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值