为什么要写这个文章?
前端在工程化/组件化上近几年飞速发展, 生态已经相当成熟, 得益于 React Vue等前端框架的普及. 组件化的方式搭建前端页面已经是每一个前端的是标配技能了, 也极大降低了前端开发的入门门槛. 对于一个没有接触过前端的人来说(比如很多后端程序员), 只要大致了解es6语法, 看一下 React 或者 Vue 的官方文档, 使用 create-react-app 脚手架工具创建一个demo app, 基本上可以在半天内搭建出一个 简单的TODO APP, 配合上 Ant Design等流行的UI组件框架, 非专业的前端也能快速搭建起一套不错的后台管理系统.
UI上得益于开源的组件, 外观看上去非常现代并且简洁, UI设计语言也是高度一致, 这时候难免有些同学会觉得, 前端是在是太简单了. 不就用开源组件跟搭建积木一样把站点搭建起来嘛
举一个简单的例子,
1 | // 需求: 写一个表单信息预览卡片, 需要实现 左侧展示表单, 右侧实时预览展示表单的填写数据 |
当然真实的需求并不会如此简单, 可能表单的输入框有十几项需要填写, 可能表单的预览展示也是有非常多的个性化展示, 在组件化思维的影响下, 一般比较好的选择是把 App 拆成多个子组件
1 | // 需求: 写一个表单信息预览卡片, 需要实现 左侧展示表单, 右侧实时展示表单的填写数据预览 |
这时候问题来了, FormInput组件里面的数据如何传递到 FormPreview中, 所以实际上上述的例子是无法实现需求的. 如何解决? 一个最简单的方法就是把value存放在App组件中, 然后 FormInput FormPreview 共用同一个对象.
我们这个场景比较简单,可能这样子也行得通, 假如组件的嵌套层级很深. 比如一颗深度为5的组件二叉树, 最底下的叶子节点组件要相互通信怎么办? 难道要把叶子节点的数据状态存在根节点组件上么? 如果这样做, 必然会导致非常冗余的props传递, 所以肯定不会直接这么搞的, 正常情况下大家都会默默打开搜索引擎, 输入 “React, 组件通信, 状态管理” 关键词, 搜索的结果大致会分为如下几类:
第一类: 原生的方式
- 父组件向子组件通信: props
- 子组件向父组件通信: 回调函数/自定义事件
- 跨级组件通信: 层层组件传递props或者使用contextAPI
- 没有嵌套关系组件之间的通信: 自定义事件
第二类: 第三方状态管理库
引入Mobx Redux等状态管理库
第三类: React Hooks
使用React Hooks, 例如useState/useReducer/useContext
下面将循序渐进的介绍上述几种解决方案.