React哲学
11.React 哲学(编写一个复杂组件的原则)
React 最棒的部分之一是引导我们思考如何构建一个应用。在这篇文档中,我们将会通过 React 构建一个可搜索的产品数据表格来更深刻地领会 React 哲学。
从设计稿开始
第一步:将设计好的 UI 划分为组件层级
首先,你需要在设计稿上用方框圈出每一个组件(包括它们的子组件)
你会看到我们的应用中包含五个组件。我们已经将每个组件展示的数据标注为了斜体。
FilterableProductTable
(橙色): 是整个示例应用的整体SearchBar
(蓝色): 接受所有的用户输入ProductTable
(绿色): 展示数据内容并根据用户输入筛选结果ProductCategoryRow
(天蓝色): 为每一个产品类别展示标题ProductRow
(红色): 每一行展示一个产品
你可能注意到,ProductTable
的表头(包含 “Name” 和 “Price” 的那一部分)并未单独成为一个组件。这仅仅是一种偏好选择,如何处理这一问题也一直存在争论。(简单的可以不用单独分一个组件,复杂的作为一个独立的组件就有必要了)
组件层级:
FilterableProductTable
SearchBar
ProductTable
ProductCategoryRow
ProductRow
第二步:用 React 创建一个静态版本
先用已有的数据模型渲染一个不包含交互功能的 UI。最好将渲染 UI 和添加交互这两个过程分开。
这是因为,编写一个应用的静态版本时,往往要编写大量代码,而不需要考虑太多交互细节;添加交互功能时则要考虑大量细节,而不需要编写太多代码。
在构建应用的静态版本时,我们需要创建一些会重用其他组件的组件,然后通过 props 传入所需的数据。props 是父组件向子组件传递数据的方式。即使你已经熟悉了 state 的概念,也完全不应该使用 state 构建静态版本。state 代表了随时间会产生变化的数据。
你可以自上而下或者自下而上构建应用:自上而下意味着首先编写层级较高的组件(比如 FilterableProductTable
),自下而上意味着从最基本的组件开始编写(比如 ProductRow
)。当你的应用比较简单时,使用自上而下的方式更方便;对于较为大型的项目来说,自下而上地构建,并同时为低层组件编写测试是更加简单的方式。
React 单向数据流(也叫单向绑定)的思想使得组件模块化,易于快速开发。
在 React 中,有两类“模型”数据:props 和 state。清楚地理解两者的区别是十分重要的
第三步:确定 UI state 的最小(且完整)表示
只保留应用所需的可变 state 的最小集合,其他数据均由它们计算产生。
可以由 state 计算产生的数据就没必要另外保存一个 state!
对于使用 props 还是 state,通过问自己以下三个问题,你可以逐个检查相应数据是否属于 state:
- 该数据是否是由父组件通过 props 传递而来的?如果是,那它应该不是 state。
- 该数据是否随时间的推移而保持不变?如果是,那它应该也不是 state。
- 你能否根据其他 state 或 props 计算出该数据的值?如果是,那它也不是 state。
非 state 的数据:
- 由父组件传来的
- 不会随时间推移而改变的
- 能根据其他 stete 或 props 计算而来的
第四步:确定 state 放置的位置
我们需要确定哪个组件能够改变这些 state,或者说拥有这些 state。
注意:React 中的数据流是单向的,并顺着组件层级从上往下传递。
对于应用中的每一个 state:
- 找到根据这个 state 进行渲染的所有组件。
- 找到他们的共同所有者(common owner)组件(在组件层级上高于所有需要该 state 的组件)。
- 该共同所有者组件或者比它层级更高的组件应该拥有该 state。
- 如果你找不到一个合适的位置来存放该 state,就可以直接创建一个新的组件来存放该 state,并将这一新组件置于高于共同所有者组件层级的位置
第五步:添加反向数据流
让数据反向传递:处于较低层级的表单组件更新较高层级组件的 state
实现方式:
父组件有一个能够修改 state 改变的回调函数,并传递给子组件
子组件的 input 修改值,使用
onChange
事件监听,并执行父组件传入的回调函数。