俗话说得好,程序 = 数据结构 + 算法。我们前端页面其实也可以简单抽象成:数据 + 逻辑。数据通常为服务端数据,逻辑可以分为两大类:无状态逻辑和有状态逻辑。
无状态逻辑,可以是公众函数、公共业务逻辑、service 处理器,因为是纯函数,可以抽象出来到处复用。
有状态逻辑,又可以分为两类:多实例有状态逻辑和单实例有状态。多实例有状态逻辑,本质上更偏向于无状态逻辑,具象一点可以理解为 vue3 composition API 和 react 的 hooks。前端应用大部分逻辑可以是无状态逻辑和多实例有状态逻辑,比较好处理。复杂的是单实例有状态逻辑。状态管理要解决的问题,也是单实例有状态逻辑的增删改查问题。下面来仔细分析一下。
单实例有状态逻辑,又可以分为,单实例非共享状态逻辑和单实例共享状态逻辑。
单实例非共享状态逻辑
单实例非共享状态逻辑,指的是状态在一个地方展示,可以背多个地方修改。为了方便说明,这里以A组件为中心:
-
A 组件的子组件要修改 A 组件的状态
-
A 组件的子组件的子组件(以及子子…组件)需要修改 A 组件的状态
-
A 组件的父组件需要修改 A 组件的状态
-
其他情况
- A 组件的父组件的父组件(以及父父…组件)需要修改 A 组件的状态
- A 组件的兄弟组件需要修改 A 组件的状态
- A 组件的兄弟组件的子组件(或父组件)需要修改 A 组件的状态
场景一:A 组件的子组件要修改 A 组件的状态
代码内聚性通常意味着可维护性越强,这个时候子组件通过暴露事件出去给 A 组件使用会是一个比较佳的方式,或者传递方法给子组件。
场景二: A 组件的子组件的子组件(以及子子…组件)需要修改 A 组件的状态
层级嵌套过多,通过暴露事件的方式一层层往上浮动,写起来繁琐,事件名称有变动得到处改。不建议事件传递的方式。有两种方式可以考虑:
- 如果子组件的子组件相对独立,可以将子组件的子组件抽离出来,作为 A 组件的直接依赖组件,类似于常见的:Form 和 FormItem 的关系。
- 在 1 不满足的情况下,用 provide/inject,直接夸组件传递。
场景三:A 组件的父组件需要修改 A 组件的状态
这种情况下出现的情况相对还是比较多,通常我们会用 ref 解决。但也要尽量控制,用 vue3.2 的 script setup 会比较好,可以明确制定导出的方法。
场景四:其他场景
因为该数据只在一个地方展示,却在八杆子不着的地方修改了,这时更应该考虑交互的合理性。在交互合理的情况下,考虑组件划分非合理性。确认交互没问题的前提下,组件划分没问题的情况下,可用发布订阅模式,或者采用下文介绍的抽离共享状态的方式。个人偏向于后者。
单实例共享状态逻辑
单实例共享状态逻辑,指的是一个状态在多个地方展示。为了方便说明,这里以A组件为中心:
- A 组件的子组件要共享 A 组件的状态
- A 组件的子组件的子组件(以及子子…组件)需要共享 A 组件的状态
- A 组件的父组件(或父父…组件)需要共享 A 组件的状态
- A 组件的兄弟组件(或兄弟组件的子子…组件、父父…组件)需要共享 A 组件的状态
场景一:A 组件的子组件要共享 A 组件的状态
props,单项数据流,经典场景。
场景二: A 组件的子组件的子组件(以及子子…组件)需要共享 A 组件的状态
层级嵌套过多,通过 props 的方式一层层往下传,写起来繁琐,名称有变动得到处改。有两种方式可以考虑:
- 如果只是子组件的子组件,层级不深还是可以考虑 props。
- 如果子组件的子组件相对独立,可以将子组件的子组件抽离出来,作为 A 组件的直接依赖组件,类似于常见的:Form 和 FormItem 的关系。
- 在 1 和 2 不满足的情况下,用 provide/inject,直接夸组件传递。
场景三:A 组件的父组件(或父父…组件)需要共享 A 组件的状态
考虑两种场景:
- 如果状态相关逻辑相对 A 组件较为独立,可以考虑状态往上提。
- 如果状态相关逻辑和 A 强关联,或者不仅仅和A 强关联,在组件划分合理的前提下,如果可遇见的类似逻辑不多,可用 readonly 锁定状态,进行状态共享,否则直接用 vuex。无法判断的话直接用 vuex。
场景四:A 组件的兄弟组件(或兄弟组件的子子…组件、父父…组件)需要共享 A 组件的状态
处理方法和场景三一致。
俗话说得好,程序 = 数据结构 + 算法。我们前端页面其实也可以简单抽象成:数据 + 逻辑。数据通常为服务端数据,逻辑可以分为两大类:无状态逻辑和有状态逻辑。
无状态逻辑,可以是公众函数、公共业务逻辑、service 处理器,因为是纯函数,可以抽象出来到处复用。
有状态逻辑,又可以分为两类:多实例有状态逻辑和单实例有状态。多实例有状态逻辑,本质上更偏向于无状态逻辑,具象一点可以理解为 vue3 composition API 和 react 的 hooks。前端应用大部分逻辑可以是无状态逻辑和多实例有状态逻辑,比较好处理。复杂的是单实例有状态逻辑。状态管理要解决的问题,也是单实例有状态逻辑的增删改查问题。下面来仔细分析一下。
单实例有状态逻辑,又可以分为,单实例非共享状态逻辑和单实例共享状态逻辑。
单实例非共享状态逻辑
单实例非共享状态逻辑,指的是状态在一个地方展示,可以背多个地方修改。为了方便说明,这里以A组件为中心:
A 组件的子组件要修改 A 组件的状态
A 组件的子组件的子组件(以及子子…组件)需要修改 A 组件的状态
A 组件的父组件需要修改 A 组件的状态
其他情况
场景一:A 组件的子组件要修改 A 组件的状态
代码内聚性通常意味着可维护性越强,这个时候子组件通过暴露事件出去给 A 组件使用会是一个比较佳的方式,或者传递方法给子组件。
场景二: A 组件的子组件的子组件(以及子子…组件)需要修改 A 组件的状态
层级嵌套过多,通过暴露事件的方式一层层往上浮动,写起来繁琐,事件名称有变动得到处改。不建议事件传递的方式。有两种方式可以考虑:
场景三:A 组件的父组件需要修改 A 组件的状态
这种情况下出现的情况相对还是比较多,通常我们会用 ref 解决。但也要尽量控制,用 vue3.2 的 script setup 会比较好,可以明确制定导出的方法。
场景四:其他场景
因为该数据只在一个地方展示,却在八杆子不着的地方修改了,这时更应该考虑交互的合理性。在交互合理的情况下,考虑组件划分非合理性。确认交互没问题的前提下,组件划分没问题的情况下,可用发布订阅模式,或者采用下文介绍的抽离共享状态的方式。个人偏向于后者。
单实例共享状态逻辑
单实例共享状态逻辑,指的是一个状态在多个地方展示。为了方便说明,这里以A组件为中心:
场景一:A 组件的子组件要共享 A 组件的状态
props,单项数据流,经典场景。
场景二: A 组件的子组件的子组件(以及子子…组件)需要共享 A 组件的状态
层级嵌套过多,通过 props 的方式一层层往下传,写起来繁琐,名称有变动得到处改。有两种方式可以考虑:
场景三:A 组件的父组件(或父父…组件)需要共享 A 组件的状态
考虑两种场景:
场景四:A 组件的兄弟组件(或兄弟组件的子子…组件、父父…组件)需要共享 A 组件的状态
处理方法和场景三一致。