React入门
React16 version
JSX
JSX -> React 元素 -> DOM
{}
大括号中可以放置任何有效的 js 表达式
JSX 本质上也是个表达式,编译后会被转为 React.createElement()
这种普通函数调用
元素渲染
元素是构成 React 应用的最小砖块
元素描述了你在屏幕上想看到的内容,与普通 DOM 不同,React 是开销极小的普通对象,React DOM 会负责更新 DOM 来与 React 元素保持一致(这个更新算法是高效的,只会进行必要的更新)
组件是由元素组成的
React 元素是不可变对象,一旦被创建,就无法更改它的子元素或者属性(代表了某个特定时刻的 UI)。更新 UI 的方式之一是创建一个全新的元素,并将其传入 ReactDOM.render()
组件 & Props
组件允许你将 UI 拆分为独立可复用的代码片段,并对每个片段进行独立构思。
函数组件:参数 props,返回 react 元素
class组件:es6 的 class 语法,在 react 中和函数组件是等效的
纯函数:不更改入参,且多次情况下调用相同的入参始终返回相同的结果
所有的 React 组件都必须像纯函数一样保护它们的 props 不被更改
State & 生命周期
state:私有的,完全受控于当前组件
this.props
和 this.state
是 React 本身设置的有特殊含义的属性,但其实也可以向 class 中随意添加(不参与数据流的)其他字段
生命周期方法:
componentDidMount()
= vue 的 mountedcomponentWillUnmount()
= vue 的 beforeDestory
更新 UI 的方式之二:state 里面(通过setState()
)修改数据,从而 React 能够知道state 变化,每次更新时都调用组件的 render 方法
正确使用 State:
除了在构造函数中其他地方都不要直接给 state 赋值的方式修改它,应该使用
setState()
state 的更新可能是异步的,React 可能会把多个
setState()
调用合并成一个调用(和 vue 类似)所以不要依赖
this.state
或this.props
的值来更新下一个状态,如果需要,可以在setState()
中传入一个函数(state, props) => {}
,其中 state 是上一个 state,props 是此次更新时被应用的 propsstate的更新会被合并,
setState()
传入的对象会 assign 到现有的 state 上,同样也是浅合并
数据是向下流动的,state 只能由本组件访问,可以通过 props 的方式向下传递,单向数据流
事件处理
this 要手动添加绑定(解释可以参考 这一篇)
条件渲染
- if
- 可以用变量储存元素
- 利用 js 的
&&
运算符 - 利用 js 的三目运算符
阻止组件渲染:render
返回 null
列表 & Key
渲染多个组件:构建元素数组,然后将数组加入 JSX 中
key(同 vue):
- 在数组的上下文中指定(通常是在
map
方法中的元素) - key 只是在兄弟节点之间必须唯一
表单
受控组件:state 是唯一数据源(与 v-model 类似,表单项的 value
赋值为 state
中的值,输入事件指定一个函数,函数内使用 setState()
改变 state -> 从而使得 value 值发生改变)
如果在受控组件上把 value 指定成了 prop 则会阻止用户更改输入
但是对于像 <input type="file" />
这种 value 只读的组件,属于非受控组件
状态提升
将多个组件中需要共享的 state 向上移动到它们的最近共同父组件中
和受控组件一样,父组件提供 value 和 onChange(或者任何命名),作为 props 传递给子组件,子组件只负责展示+监听值变化时通过调用父组件传来的处理函数把值传上去
任何可变数据应当只有一个相对应的唯一数据源,应当依靠自上而下的数据流,而不是尝试在不同组件间同步 state
如果某些数据可以由 props 或 state 推导得出,那么它就不应该存在于 state 中
组合 vs 继承
包含关系:组合
props.children(类似于 vue 匿名 slot);或者自己命名 props(类似于 vue 具名 slot)
特例关系:props
通过给一般组件指定 props 来定制特殊组件
继承关系:React 不需要继承来构建组件层次,props 和组合能够完成组件间复用 ui(包括外观和行为),如果需要复用非 ui 的功能,建议将其提取为一个单独的 js 模块,组件可以直接 import 而无需通过 extend 继承它们
React 哲学
将设计好的 UI 划分为组件层级
圈出每个组件,并以合适的名称命名
划分组件的过程中,根据单一功能原则判定组件的范围
用 React 创建一个静态版本
先用已有的数据模型渲染一个不包含交互功能的 UI(编写一个应用的静态版本时,往往需要编写大量代码而不需要考虑太多交互细节;添加交互功能时则要考虑大量细节而不需要编写太多代码)
只使用 props,完全不应该使用 state 构建静态版本(state 代表了随时间会产生变化的数据,应当仅在实现交互时使用)
这些组件目前只需提供
render()
方法用于渲染,最顶层的组件通过 props 接受数据模型,单向数据流确定 UI state 的最小(且完整)表示
DRY: Don’t Repeat Yourself,只保留应用所需的可变 state 的最小集合,其他数据均由它们计算产生
非父组件 props 传递来的、随着时间推移改变的、不能根据其他 state 或 props 计算出该数据的值 => 是 state
确定 state 放置的位置
找到根据这个 state 进行渲染的所有组件 -> 找到他们的共同所有者组件(在组件层级上高于所有需要该 state 的组件)-> 该共同所有者或者比它层级更高的组件应该拥有该 state -> 如果你找不到一个合适的位置来存放该 state,可以直接创建一个新的组件来存放,并将这一新组件置于高于共同所有者组件层级的位置
添加反向数据流
开始自下而上调 callback 传递数据上去给 state 所在