重读 React | React 核心概念
1. JSX
JSX 是 JavaScript 的语法扩展。 JSX 可以很好地描述 UI 可交互的本质。
JSX 可以生成 React 元素。
React 认为渲染逻辑本质上与 UI 逻辑内在耦合。 UI 逻辑:绑定事件处理,状态随时间变化的逻辑,如何正确展示数据。 React 将标记与逻辑共同放入组件的松散耦合单元中。
zr: 对 JSX 可以很好地描述 UI 可交互的本质,进行了解释。
zr: 渲染逻辑是指业务逻辑。
zr: UI 逻辑,涉及事件、状态、数据。触发事件,显示状态,展示数据,这些是 UI 的逻辑,至于事件处理函数就不属于 UI 逻辑了。
JSX 也是表达式。
React.createElement() 创建 React 元素。
2. 渲染元素
元素是 React 应用中最小的构建模块。
与浏览器 DOM 不同,React Elements 是普通的对象,而且创建成本低。React DOM 会负责更新 DOM 去同 React Elements 保持一致。
渲染 React Element 到 DOM 上:
- 将 DOM element 传入
ReactDOM.createRoot() - 将 React element 传入
root.render()
2.1 更新已渲染的元素
React Elements 是不可变的。意味着 React Elements 一旦创建你就不能修改它的子元素或者属性。 React Elements 代表某个时刻的 UI。
In our experience, thinking about how the UI should look at any given moment, rather than how to change it over time, eliminates a whole class of bugs.
zr: 将 UI 理解为特定时刻的呈现比将 UI 理解为随时间改变,可以避免一类错误。
3. Components & Props
组件的出现,可以让我们将 UI 拆分为单独可复用的代码片段,并独立构思每个片段。
组件,从概念上类似于 JavaScript 函数,接收任意输入(props),返回用于描述页面展示内容的 React Elements。
3.1 Props 只读
所有 React Components 都应该像纯函数一样对待它们的 Props。
3.x
组件和元素的区别是什么? 元素可以是 DOM 标签也可以是自定义组件,是否元素概念就等同于组件?
zr: React Components 和 React Elements 就是同一个东西。将一个逻辑所有相关的 elements 组织成一个新的 Element,这个新的 Element 就是 Components。 zr: 我上面这个表述是错误的。造成这样的理解错误是由于将
Component等同于了<Component />zr: React Components 是函数,它的返回值是 React Elements。在代码中书写
<Component />是 React Components 的执行结果,即 React Elements。
4. State & Lifecycle
State 与 Props 类似,但 State 是 Components 私有的,并完全受控于当前 Components。
4.1 正确使用 State
- 不要直接修改 State。使用
this.setState(),只在构造函数中使用this.state赋值。 - State 更新可能是异步的。处于性能考虑,React 可能会把多个
setState()调用合并成一个调用。 - State 的更新会被合并(浅合并)。
this.state 和 this.props 可能是异步更新,所有不要依赖他们的值来更新下一个状态。可以使用回调函数,该回调函数接受两个参数,上一次的 state 和更新后的 props。
zr: 为了性能,增加了理解的难度。 zr: 虽然告诉了怎样处理,但是引入了什么时候会产生这样的问题,以及传入回调函数后怎样解决这样的问题的困惑。
4.2 数据是向下流动的
"top-down" or "unidirectional" data flow.
5. 事件处理
React Elements 的事件处理和 DOM 类似,但也有不同:
- 采用小驼峰命名(camelCase)。
- 需要传入一个函数作为事件处理函数,而不是一个字符串。
- 阻止默认行为不能通过返回
false,必须显式的使用preventDefault。 - React 中的
event是一个合成事件(Synthetic Event)。React 根据 W3C 规范来定义合成事件。 - 不要使用
addEventListener为已创建的 DOM 元素添加监听器,只需要在该元素初始渲染的时候添加监听器。
在 Class Components 中,箭头函数的事件处理函数作为 props 传入子组件时,这些组件可能进行额外的重新渲染。
6. 条件渲染
元素变量。使用变量存储元素。
运算符 &&,false 的表达式会使 && 后面的元素被跳过,但会返回 false 表达式。
三目运算符。
阻止组件渲染,render 中返回 null,但并不会影响最近生命周期。
7. Lists & Keys
key 帮助 React 识别哪些元素改变了。
key 会传递信息给 React,并不会传递给组件。
不指定 key 时,React 默认使用索引作为 key 值。
8. 表单
受控组件上指定 value 的 prop 会阻止用户更改输入。但如果 value 为 undefined 或 or 时,输入仍可以编辑。
Formik 保单验证、追踪访问字段、处理表单提交的完整解决方案。
9. 状态提升
多个组件需要反映相同的变化数据,建议将共享状态提升到最近的共同父组件中。
zr: 基于自上而下的数据流的思想。
10. Composition vs Inheritance
组件之间是包含关系,使用 children props。
组件之间是特例关系,“特例” 组件可以通过 props 定制并渲染 “一般” 组件实现。
props 和组件提供了清晰而安全的定制组件外观和行为的灵活方式。组件可以接受任意 props,包括基本类型、React Elements、函数。
zr: props 和组件完全可以满足定制组件的需求。
组件间复用非 UI 的功能,将其提取为一个单独的 JavaScript 模块,如函数、对象、类。组件可以直接 import 无需 extend 它们。
11. React 编程思想
- 划分 UI 的组件层次。
- 用 React 创建一个静态版本。
- 确定 UI state 的最小且完整表示。
- 确定 state 放置的位置。
- 添加反向数据流。
11.1 划分 UI 的组件层次
组件按照单一功能原则划分。一个组件只做一件事情。
UI 和数据模型都会倾向遵循相同的信息架构。 划分 UI 为组件,每个组件匹配数据模型的一部分。
11.2 用 React 创建一个静态版本
先用已有的数据模型渲染一个不包含交互的 UI。 创建一个静态的版本需要些大量的代码,但不用大量的思考。 添加交互需要大量思考,不需要写大量的代码。
创建组件是会重用其他组件,通过 props 向其他组件传入其所需的数据。 构建静态版本不要使用 state。
构建简单应用时,自上而下更方便。 构建复杂应用时,自下而上更简单。
11.3 确定 UI state 的最小且完整的表达
React 中 UI 交互实现,需要有触发基础数据模型改变的能力。React 通过 state 来实现这个能力。
根据 Don't Repeat Yourself 原则,找出应用中所需的 state 的最小集合。
哪些可能不是 state:
- props 不是 state。
- 不随时间而改变的不是 state。
- 通过其他 state 或 props 计算得到的不是 state。
11.4 确定 state 放置的位置
zr: 确定 state 放置位置的意义在于降低应用状态之间同步的复杂度。
11.5 添加反向数据流
添加反向数据流:底层组件可以更新高层组件的 state。