一篇笔记, 参考官方教程并且加上了很多批注

React: React.Component Overview

Overview

React.Component 是一个抽象基类, 基本结构:

class Greeting extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

最小配置就是一个render()函数

The Component Lifecycle

Mounting

当一个 component 加载并且加入 DOM 的时候执行

These methods are called when an instance of a component is being created and inserted into the DOM:

Updating

当一个 component 重新渲染的时候执行

An update can be caused by changes to props or state. These methods are called when a component is being re-rendered:

Unmounting

删除时执行

This method is called when a component is being removed from the DOM:

Error Handling

当 render 的时候报错

This method is called when there is an error during rendering, in a lifecycle method, or in the constructor of any child component.

Functions

Render()

这个函数可以返回以下内容:

  • React elements. Typically created via JSX. An element can either be a representation of a native DOM component (<div />), or a user-defined composite component (<MyComponent />).
  • String and numbers. These are rendered as text nodes in the DOM.
  • Portals. Created with ReactDOM.createPortal.
  • null. Renders nothing.
  • Booleans. Render nothing. (Mostly exists to support return test && <Child /> pattern, where test is boolean.)

用于返回一个 DOM 时并且用上某些条件的情况

几个渲染限制
  • When returning null or false, ReactDOM.findDOMNode(this) will return null.
  • render() will not be invoked if shouldComponentUpdate() returns false.
使用的原则

The render() function should be pure, meaning that it does not modify component state, it returns the same result each time it』s invoked, and it does not directly interact with the browser.

render()一般不要改变 state 里面的内容, 保证这个函数就做单一的渲染这个事情

If you need to interact with the browser, perform your work in componentDidMount() or the other lifecycle methods instead. Keeping render() pure makes components easier to think about.

Fragments

render()这个函数里面也可以返回一个 DOM 数组:

render() {
  return [
    <li key="A">First item</li>,
    <li key="B">Second item</li>,
    <li key="C">Third item</li>,
  ];
}

React V16.2 之后也可以用这个方法

render() {
  return (
    <React.Fragment>
      <li>First item</li>
      <li>Second item</li>
      <li>Third item</li>
    </React.Fragment>
  );
}

区别就在于不需要提供key

constructor(props)

  • mount状态之前执行这个函数
  • 可以通过super(props)调用父类的方法
  • 并且如果不调用super(props)的话, this.props就会变成undefined
  • 应该在这个函数里初始化this.state
  • 并且不要在这个函数里使用setState()
  • 当然如果我需要绑定函数, 也没有状态变化的话, 就完全不需接入这个接口了

componentWillMount()

  • mount发生的时候立刻执行
  • render()之前执行
  • 但是和render()不一样, setState()之后, 不会重复执行一次

componentDidMount()

  • mount状态之后执行这个函数
  • 对于 DOM 的一系列 init 可以放在这个地方
  • 进行各类网络请求的最佳地点, 比如 AJAX 获取数据之类的
  • 注册subscription的最佳地点, 当然不要忘记在componentWillUnmount()注销subscription
  • 关于 subscription
  • 就是类似于 GQL 之类的玩意
  • setState()之后, 重复执行一次
  • 上面这个用法的时候一定要注意性能问题

componentWillReceiveProps(nextProps)

  • 无论新的和旧的 prop 是否相等都会执行这个函数
  • 另外需要注意的是mount状态的时候并不会执行这个函数, 也就是说, 初始化的时候并不会执行这个函数

这个很容易理解了

有一些情况就是不通过state而通过props来刷新的情况, 就可以在这个函数里面判断新的和旧的 prop 是否相等, 并根据判断结果刷新state

shouldComponentUpdate(nextProps, nextState)

  • 在新的 prop 或者 state 接收到的时候, 并且在刷新之前执行
  • 默认情况下返回true, 这个函数会导致render()刷新
  • 另外就算是返回false, 也无法防止子模块的刷新
  • Currently, if shouldComponentUpdate() returns false, then componentWillUpdate(), render(), and componentDidUpdate()

componentWillUpdate(nextProps, nextState)

  • 在新的propsstate获取到之前执行
  • 因此可以在这儿执行一些 update 的准备活动
  • 当然不要在这里面修改stateprops
  • 如果非要修改的话, 最好使用componentWillReceiveProps()
  • 这个函数的是否执行与shouldComponentUpdate()的返回值相关

componentDidUpdate(prevProps, prevState)

  • 这个就是在更新时候执行
  • 对于一些 DOM 的处理可以放在这个地方
  • 另外可以在这个地方判断一下props是否改变, 并根据这个结果决定是否发送 http 请求
  • 这个函数的是否执行与shouldComponentUpdate()的返回值相关

componentWillUnmount()

  • 当元素销毁的时候执行, 因此适合执行一些善后工作
  • 比如计时器的关闭, 网络请求关闭, subscriptions 的清理等等

componentDidCatch(error, info)

(待补充)

setState(updater[, callback])

  • 修改界面的主要方式
  • 最好将这个函数看成一个请求, 因为实现更新可能会有一定的延迟, 也有可能将一系列的更新批次完成
  • 正因为不会立刻执行, 对于state的读取就必须要小心, 推荐使用componentDidUpdate()
  • 除非shouldComponentUpdate()返回了false, 否则这个函数的执行一定会重新渲染界面
  • 因此通过一定条件判断是否使用这个函数, 可以避免一些不必要的重新渲染
使用方法
  • 第一个参数是个 updater function
  • 第一个参数也可以直接放一个 Obj, 会被自动 merge 到state
  • 第二个参数是一个 callback, 当state修改之后执行
updater 的使用方法
this.setState((prevState, props) => {
  return {counter: prevState.counter + props.step};
});
updater 的使用方法 2
this.setState({quantity: 2})
异步执行

这个函数的执行是异步的, 因此如果有这样的执行:

Object.assign(
  previousState,
  {quantity: state.quantity + 1},
  {quantity: state.quantity + 1},
  ……
)

最后可能仅仅加了 1

因此如果要改变的状态和历史状态有关, 那么最好使用 updater 函数

this.setState((prevState) => {
  return {quantity: prevState.quantity + 1};
});

component.forceUpdate(callback)

  • 对于当前模块强行调用render(), 并且忽略shouldComponentUpdate()的限制
  • 同时也会调用所有子模块的render(), 但是会根据它们的生命周期判断shouldComponentUpdate()的值
  • 当然不推荐使用这个方法, 尽可能仅仅通过props以及state进行重新渲染

Class Properties

defaultProps

这个是直接给一个模块提供默认的prop

class CustomButton extends React.Component {
  // ……
}

CustomButton.defaultProps = {
  color: 'blue'
};

……

  render() {
    return <CustomButton /> ; // props.color will be set to blue
  }

但是注意, 不管给任何值, 只要给了值, 就一定会覆盖掉默认值

  render() {
    return <CustomButton color={null} /> ; // props.color will remain null
  }

displayName

这个其实是 debug 的时候方便查看用的

相关文章: https://reactjs.org/docs/higher-order-components.html#convention-wrap-the-display-name-for-easy-debugging

Instance Properties

props

没什么好说的了

  • this.props.children这个比较特别,这个包含了所有子标签的 JSX

state

  • 永远不要直接修改这个词一定要通过setState()来进行修改