最近在看 React 的文档,因为之前有使用 Vue 的经验,所以其中的概念理解起来倒是不算难,不过 React 的文档给我的感觉并不只是教我怎么写 React,怎么使用它的语法,它更多的是在教我如何从组件的角度出发,编写一个健壮的 web app。
以前在写 Vue 组件的时候,通常是使用现有的基础组件库,然后拼装成一个 page component,所有数据都由 page component 管理,通过 props 将数据分发给子组件,但是以前并没有思考过为什么要这样做,只是因为大家都这样写代码,所以我也这样写代码。
而 React 哲学告诉了我们,在面对一份新的设计稿时,应当如何从最基本的层面去思考如何构建这个页面。
第一步:通过 UI 来划分组件
其实在设计领域,也一直在推崇组件化,即设计师在设计 UI 时,也需要将每个功能点按组件划分,并不是一味地堆叠元素。
通过单一功能原则来判断组件的分为
第二步:创建一个静态版本
这一步通俗来说应该就是切图了,通过 mock data 构建一个没有交互能力的静态版本
第三步:确定 UI state 的最小(且完整)表示
确定哪些数据是需要组件自身来更改。
通过可以从以下三步判断:
- 该数据是否是由父组件通过 props 传递而来的?如果是,那它应该不是 state。
- 该数据是否随时间的推移而保持不变?如果是,那它应该也不是 state。
- 这一步我的理解是,该数据是否可由组件自身的交互操作改变它
- 你能否根据其他 state 或 props 计算出该数据的值?如果是,那它也不是 state。
第四步:确定 state 放置的位置
假设现在拥有 parent compoent、child1 component 和 child2 component(后文简称 p、c1、c2),c2 中的数据由 p 通过 props 传递给它,c1 自身维护一份 state,但 c2 中的数据依赖 c1 的 state,那么此时应该将 c1 的 state 提升到 p 中,并通过 props 传递给 c1
以下是官方给出的判断方法:
- 找到根据这个 state 进行渲染的所有组件。
- 找到他们的共同所有者(common owner)组件(在组件层级上高于所有需要该 state 的组件)。
- 该共同所有者组件或者比它层级更高的组件应该拥有该 state。
- 如果你找不到一个合适的位置来存放该 state,就可以直接创建一个新的组件来存放该 state,并将这一新组件置于高于共同所有者组件层级的位置。
第五步:添加反向数据流
因为 React 中的数据使用单项数据流的方式进行传递,所以在在第四步中,我们将 c1 的 state 提升到 p 中,p 通过 props 传递给 c1,那么如果 c1 的交互操作需要改变这个数据,应该怎么办?数据不是双向绑定的,我们没办法通过在 c1 中修改这个数据来同步改变 p 中的这个数据。
这时只能通过反向数据流来实现了,其实反向数据流并不是什么 magic,很简单:
- c1 component emit event
- event callback called
- callback call on[PropsData]Change
- p component defined on[PropsData]Change function
- on[PropsData]Change function change p component state
- on[PropsData]Change bind
this