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.propsthis.state 是 React 本身设置的有特殊含义的属性,但其实也可以向 class 中随意添加(不参与数据流的)其他字段

生命周期方法:

  • componentDidMount() = vue 的 mounted
  • componentWillUnmount() = vue 的 beforeDestory

更新 UI 的方式之二:state 里面(通过setState())修改数据,从而 React 能够知道state 变化,每次更新时都调用组件的 render 方法

正确使用 State:

  • 除了在构造函数中其他地方都不要直接给 state 赋值的方式修改它,应该使用 setState()

  • state 的更新可能是异步的,React 可能会把多个 setState() 调用合并成一个调用(和 vue 类似)

    所以不要依赖 this.statethis.props 的值来更新下一个状态,如果需要,可以在 setState() 中传入一个函数 (state, props) => {} ,其中 state 是上一个 state,props 是此次更新时被应用的 props

  • state的更新会被合并,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 哲学

  1. 将设计好的 UI 划分为组件层级

    圈出每个组件,并以合适的名称命名

    划分组件的过程中,根据单一功能原则判定组件的范围

  2. 用 React 创建一个静态版本

    先用已有的数据模型渲染一个不包含交互功能的 UI(编写一个应用的静态版本时,往往需要编写大量代码而不需要考虑太多交互细节;添加交互功能时则要考虑大量细节而不需要编写太多代码)

    只使用 props,完全不应该使用 state 构建静态版本(state 代表了随时间会产生变化的数据,应当仅在实现交互时使用)

    这些组件目前只需提供 render() 方法用于渲染,最顶层的组件通过 props 接受数据模型,单向数据流

  3. 确定 UI state 的最小(且完整)表示

    DRY: Don’t Repeat Yourself,只保留应用所需的可变 state 的最小集合,其他数据均由它们计算产生

    非父组件 props 传递来的、随着时间推移改变的、不能根据其他 state 或 props 计算出该数据的值 => 是 state

  4. 确定 state 放置的位置

    找到根据这个 state 进行渲染的所有组件 -> 找到他们的共同所有者组件(在组件层级上高于所有需要该 state 的组件)-> 该共同所有者或者比它层级更高的组件应该拥有该 state -> 如果你找不到一个合适的位置来存放该 state,可以直接创建一个新的组件来存放,并将这一新组件置于高于共同所有者组件层级的位置

  5. 添加反向数据流

    开始自下而上调 callback 传递数据上去给 state 所在