最近在看 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