官方网站建设的四个步骤,哪个网站专门做灵异文,王业美三个字组成的子,昭通网站建设兼职写在前面
本文中提及的use开头的函数#xff0c;都出自与我的 ComposeHooks 项目#xff0c;它提供了一系列 React Hooks 风格的状态封装函数#xff0c;可以帮你更好的使用 Compose#xff0c;无需关系复杂的状态管理#xff0c;专心于业务与UI组件。
这是系列文章的第…写在前面
本文中提及的use开头的函数都出自与我的 ComposeHooks 项目它提供了一系列 React Hooks 风格的状态封装函数可以帮你更好的使用 Compose无需关系复杂的状态管理专心于业务与UI组件。
这是系列文章的第四篇前文
在Compose中使用useRequest轻松管理网络请求在Compose中使用状态提升我提升个P…Provider在Compose中父组件如何调用子组件的函数 什么是 MVI
什么是 MVI想必你也看过很多博客了其实简单说就是明确分离数据模型Model、用户界面View和用户意图Intent也称为事件、动作以实现UI的响应式和可预测的更新。
它与 MVVM 其实区别不大有别于 MVVM 的是MVVM 将耦合代码按照职责区分拆分文件。借助 LiveData 或者 DataBinding 将 VM 中数据更新直接驱动 V 层实现了 V 层与 M 层之间的解耦。
得力于 Compose 带来的状态驱动视图能力我们可以理解 MVI 思想为用户发出事件事件驱动状态变化状态驱动 UI 变化。这也就是所谓的事件向上状态向下事件从组件发出单一可信来源的状态驱动组件更新。
从这一思想出发我们可以理解为谁持有状态谁就是 M 层。那么过去的 MVVM 的文件拆分将会变得相对松散我们完全可以摒弃过去那种全屏式思想不再根据屏幕创建一个 VM 大管家。而是拆分成职责、粒度更细小的组件思想。
当然使用 MVVM 我们一样可以做到类似的效果但是 MVI 将它流程化、标准化所以可以理解为其实 MVI 就是一个有一定模板的更优秀的 MVVM。
过去我们的 VM 层其实也很重一个复杂的页面数个网络接口都被仍在一个 VM 中鉴于不同开发者的水平的参差我们项目中甚至有一个 VM 文件中持有了20多个 LiveData可以说完全违背了 MVVM 的初衷。
同样的想必你已经看了很多在 Compose 中使用 ViewModel 来实现 MVI 的文章了吧我甚至看过回字的四种写法它真的有这么复杂么在 Compose 中我们还需要这样的一位大管家么虽然很多例子、甚至官方的 demo都还在使用 ViewModel但是这是一种无法回避的取舍还是既往路线的惯性。
在一些场景下我们完全可以更组件化思维在更小粒度上应用 MVI。今天你可以试试一点新东西useReducer通过它我将进一步阐述我所说的松散的、组件下的 MVI 思想。
我们需要 VM 么
MVI 相关文章中你可能会看到一个观点纯函数给定相同的输入时总是产生相同的输出并且不产生任何副作用的函数。
我们构建一个改变状态的函数称之为 reducer 函数将上一个状态、Intent也成为 event、action作为函数的入参将返回值作为新的状态应用于组件只要这个 reducer 函数是 纯函数我们就实现了可预测的更新。
现在我们来构建一个最简单的例子
// 构建状态类型
data class SimpleData(val name: String,val age: Int,
)// Intent、我们一半习惯称之为action使用 sealed interface可以方便的实现
sealed interface SimpleAction {data class ChangeName(val newName: String) : SimpleActiondata object AgeIncrease : SimpleAction
}// 构建一个 Reducer 函数泛型是状态的类型
val simpleReducer: ReducerSimpleData { prevState: SimpleData, action: Any -when (action) {is SimpleAction.ChangeName - prevState.copy(name action.newName)is SimpleAction.AgeIncrease - prevState.copy(age prevState.age 1)else - prevState}
}reducer 函数中我们要使用 不可变 数据data class 就是最好的选择通过 copy 函数返回新的状态。
这些代码要么是类型声明、要么是一个纯函数他们与最终组件息息相关但是他们并需要放到一个 ViewModel 类中再想一想我们需要 ViewModel 么
上面的代码几乎已经是 MVI 的完整实现了M层状态SimpleDataI层由Action、Reducer函数构成。
他们非常简单、容易理解而且可以方便的扩展规范了M层变化你不能直接修改状态必须通过传递 Action 给 Reducer 函数驱动状态变化。
再来看看我们的 V 层需要做什么
Composable
fun UseReducerExample() {val (state, dispatch) useReducer(simpleReducer, initialState SimpleData(default, 18))val (input, setInput) useState()Surface {Column {Text(text UserName: $state.name)Text(text UserAge: $state.age)OutlinedTextField(value input, onValueChange setInput)TButton(text changeName) {dispatch(SimpleAction.ChangeName(input))}TButton(text 1) {dispatch(SimpleAction.AgeIncrease)}}}
}我们只需要使用useReducer函数传入 Reducer 函数与一个初始状态initialState通过解构声明语法可以轻松的拿到状态、dispatch函数。
然后在组件中使用即可。
我们不一定需要 VM
现在我可以回答我之前的问题了我们真的需要么
很多场景我们其实并不需要将状态从 VM 中拆解、粒化成为更小的一个个组件在组件文件中直接声明这些状态类型、Action、Reducer 函数然后通过 useReducer 函数即可。
在大多数场景也许我们根本就用不上 VM 带给我们的好处它在 View 体系是那么重要但是在 Compose 中我认为有点可有可无了。
比如生命周期感知除非你要使用旋转屏幕下的状态保持大多数应用都是锁方向的
比如数据共享了解一下状态提升了解一下 useContext
如果你是旧的 MVVM 项目改造那么使用 vm 改造成本比较小如果你是新项目我觉得一般的场景完全没有必要继续使用 VM 了。
探索更多
项目开源地址junerver/ComposeHooks
MavenCentralhooks
implementation(xyz.junerver.compose:hooks:1.0.8)欢迎使用、勘误、pr、star。