React 组件化

组件分类

React的组件相对于Vue更加的灵活和多样,按照不同的方式可以分成很多类组件:

  • 根据组件的定义方式,可以分为:函数组件(Functional Component )和类组件(Class Component)
  • 根据组件内部是否有状态需要维护,可以分成:无状态组件(Stateless Component )和有状态组件(Stateful Component)
  • 根据组件的不同职责,可以分成:展示型组件(Presentational Component)和容器型组件(Container Component)

类组件

重要特点如下:

  • 组件的名称是大写字符开头(无论类组件还是函数组件)
  • 类组件需要继承自 React.Component
  • constructor是可选的,我们通常在constructor中初始化一些数据
  • 类组件必须实现render函数

render函数的返回值

当render 被调用时,它会检查 this.props 和this.state 的变化井返回以下类型之一:

  • React 元素:

    • 通常通过 JSX 创建
    • 例如,<div/>会被 React 渲染为 DOM 节点,<MyComponent/>会被 React 渲染为自定义组件
    • 无论是<div/> 还是<MyComponent/>均为 React 元素。
  • 数组或 Fragments:使得render 方法可以返回多个元素(React会默认展开数组)。

  • Portals:可以渲染子节点到不同的 DOM 子树中。

  • 字符串或数值类型:它们在 DOM 中会被渲染为文本节点

  • boolean或 null:什么都不渲染

函数组件

函数组件是使用function来进行定义的函数,只是这个函数会返回和类组件中render函数返回一样的内容,特点有

  • 没有生命周期,也会被更新并挂载,但是没有生命周期函数(hooks实现,具体之后总结)
  • this关键字不能指向组件实例(因为没有组件实例)
  • 没有内部状态 (state),但是可通过useState实现

生命周期

image-20221022173242824

上图为生命周期图示(旧),可以理解以下过程:

  1. 初始化阶段: 由ReactDOM.render()触发—初次渲染

    1. constructor()

    2. componentWillMount()

    3. render()

    4. componentDidMount()

  2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发

    1. shouldComponentUpdate()
    2. componentWillUpdate()
    3. render()
    4. componentDidUpdate()
  3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发

  4. componentWillUnmount()

image-20221025201415153

上图为生命周期图示(新),可以理解以下过程:

  1. 初始化阶段:由ReactDOM.render()触发—初次渲染

    1. constructor()

    2. getDerivedStateFromProps

    3. render()

    4. componentDidMount()

  2. 更新阶段: 由组件内部this.setSate()或父组件重新render触发

    1. getDerivedStateFromProps

    2. shouldComponentUpdate()

    3. render()

    4. getSnapshotBeforeUpdate

    5. componentDidUpdate()

  3. 卸载组件: 由ReactDOM.unmountComponentAtNode()触发

    1. componentWillUnmount()

常用生命周期

  1. Constructor

    1. 如果不初始化 state 或不进行方法绑定,则不需要为 React 组件实现构造函数

    2. constructor中通常只做两件事情:

      1. 通过给 this.state 赋值对象来初始化内部的state

      2. 为事件绑定实例(this)

  2. componentDidMount

    1. componentDidMount() 会在组件挂载后(插入 DOM 树中)立即调用
    2. componentDidMount中通常进行哪里操作呢?
      1. 依赖于DOM的操作可以在这里进行
      2. 在此处发送网络请求就最好的地方
      3. 可以在此处添加一些订阅(会在componentWillUnmount取消订阅)
  3. componentDidUpdate

    1. componentDidUpdate() 会在更新后会被立即调用,首次渲染不会执行此方法
      1. 当组件更新后,可以在此处对 DOM 进行操作
      2. 如果你对更新前后的 props 进行了比较,也可以选择在此处进行网络请求;(例如,当 props 未发生变化时,则不会执行网络请求)
  4. componentWillUnmount

    1. componentWillUnmount() 会在组件卸载及销毁之前直接调用
      1. 在此方法中执行必要的清理操作
      2. 例如,清除 timer,取消网络请求或清除在 componentDidMount() 中创建的订阅等

不常用生命周期

  • getDerivedStateFromProps:state 的值在任何时候都依赖于 props时使用,该方法返回一个对象来更新state
  • getSnapshotBeforeUpdate:在React更新DOM之前回调的一个函数,可以获取DOM更新前的一些信息(比如说滚动位置);

将废弃生命周期

  1. componentWillMount
  2. componentWillReceiveProps
  3. componentWillUpdate

目前在使用时需要加上UNSAFE才能使用,以后可能会被彻底废弃,不建议使用

React中的插槽

react中没有Vue中的插槽属性,但是我们可以通过一些方法实现相同的方法

  1. 每个组件都可以获取到props.children:它包含组件的开始标签和结束标签之间的内容,之间的内容将以数组的形式存放,我们只需要通过下边取得内容放置即可,但是通过children实现的方案虽然可行,但是有一个弊端:通过索引值获取传入的元素很容易出错,不能精准的获取传入的原生;
  2. 另外一个种方案就是使用 props 实现:通过具名的属性,可以让我们在传入和获取时更加的精准

Context的使用

理解

一种组件间通信方式, 常用于【祖组件】与【后代组件】间通信

使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
1) 创建Context容器对象:
const XxxContext = React.createContext()

2) 渲染子组时,外面包裹xxxContext.Provider, 通过value属性给后代组件传递数据:
<xxxContext.Provider value={数据}>
子组件
</xxxContext.Provider>

3) 后代组件读取数据:

//第一种方式:仅适用于类组件
static contextType = xxxContext // 声明接收context的第一种方式
myClass.contextType = xxxContext //声明接收context的第二种方式
this.context // 读取context中的value数据

//第二种方式: 函数组件与类组件都可以
<xxxContext.Consumer>
{
value => ( // value就是context中的value数据
要显示的内容
)
}
</xxxContext.Consumer>

本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!