React 参考文档(基于v16.2.0) 02 : React.Component

React.Component

组件(Component)让你可以把UI分成独立可重用的片段,可以独立思考(译注:它们的关注点是分离的)。React.ComponentRecat库顶层API提供

概述

React.Component是一个抽象基类,直接使用该类几乎没有什么意义。一般情况下,你需要继承该类构造自己的组件。继承该类实现自己的组件时,至少需要定义自己的 render() 方法。

通常情况下,你需要这样来定义一个React Component组件:

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

如果你使用的不是ES6,那么你需要使用模块 create-react-class,这里有更多的参考信息 : Using React without ES6

请注意我们不建议你创建自己的组件基类。在React,代码重用主要通过组合(composition)而不是继承(inheritance)完成。看一下这些一般场景你可以感觉一下如何使用组合(composition)。

组件生命周期(Component Lifeycycle)

每个组件都有几个”生命周期方法”你可以重写用来在处理过程中的特定时机执行一些你的代码逻辑。
will开头的生命周期方法会在某些事情发生之前被调用,而以did开头的方法会在某些事情发生之后被调用。

组件挂载(Mounting)

下面方法会在组件实例被创建和插入到DOM树中时被调用 :

组件更新(Updating)

一个组件的属性/状态(props/state)发生变化时会引起更新。以下方法在一个组件被渲染时会被调用 :

组件卸载(Unmounting)

当一个组件被从DOM树中移除时,以下方法会被调用:

错误处理(Error Handling)

当组件在它的渲染过程中,生命周期方法执行过程中,或者任意子组件的构造方法执行过程中出现错误,以下方法会被调用:

其他API方法

每个组件还都提供了以下API:

类属性

实例属性

参考文档(Reference)

渲染方法 render()

render()

render()方法是必须要实现的(required)。
当被调用时,他会检查this.propsthis.state,并且其返回结果类型如下 :

  • React元素(elements) 通常通过JSX创建。这个元素可能是一个代表原生DOM组件的<div />,或者一个用户自定义的组合组件类型(<MyComponent />).
  • 字符串和数字(String and numbers) 用来处理成DOM中的文本(text)节点。
  • PortalsReactDOM.createPortal创建。
  • null 什么都没有处理时返回null
  • 布尔变量(Booleans) 什么都没有处理,主要用于支持这种使用模式return test && <Child />,这里test是一个布尔类型。

函数render()必须是纯粹的,也就是说,他不能修改组件的状态,组件状态不变时多次调用render()必须返回同样结果,而只使用数据进行渲染输出,它也不能直接和浏览器交互(译注:比如不能跟浏览器DOM直接交互)。

如果你想和浏览器直接交互,在componentDidMount()或者其他生命周期方法里面做。保持render()纯粹会让你的组件理解起来更简单。

注意: 如果shouldComponentUpdate()返回false,render()不会被调用。

片段 (Fragments)

render()方法也可以通过数组的形式返回多个元素,如下所示 :

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

注意: 不要忘记给片段(fragment)中的元素设置key属性,否则会提示有关key的警告。

React 16.2.0,上面的效果可以等效地通过片段方式来实现,这种方式对于静态元素不需要设置key属性 ,如下例子所示 :

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

构造方法 constructor()

constructor(props)

一个React组件的构造方法会在组件挂载前被调用。当实现一个组件的构造方法时,该方法调用其它任何其他语句前必须首先调用super(props),否则this.props在构造方法中会是未定义的(undefined),这可能会导致bug。

在构造方法中要避免任何副作用(side-effect)和订阅(subscription)。对于这些使用情况,使用componentDidMount()

构造方法是初始化组件状态(state)的合适位置。要在构造方法中初始化组件状态,需要直接将表示状态的对象赋值给this.state而不要尝试在构造方法中使用setState()

构造方法通常也用于绑定类实例的事件处理器(event handler)。

如果你既不初始化组件状态,也不需要绑定方法,那你就没有必要实现你的React组件的构造方法。

在一些非常情况下,可以基于属性props初始化状态state。这样的做法相当于”分支(forks)”了属性props并且使用属性props的初始值设置了状态state。这里是一个有效的React.Component子类构造方法的例子 :

constructor(props) {
  super(props);
  this.state = {
    color: props.initialColor
  };
}

这种模式使用起来需要小心的是状态state并不会跟着属性props的变化而变化。除了保持属性props和状态state同步的手段,经常情况下你更应该使用状态提升方法。

如果你确实将属性props通过上面说的方式”分叉(fork)”到了状态state,那么你就很可能也需要实现方法componentWillReceiveProps(nextProps)来保持属性props和状态state的同步。但是状态提升方法更简单而且不容易出bug。

componentWillMount()

componentWillMount()

componentWillMount()在挂载即将发生时被调用。它会在render()之前被调用,在该方法中同步调用setState()方法不会额外触发一次渲染(译注:也就是不会引起一次额外的render()调用)。

一般情况下,我们建议使用构造方法而不是该方法完成相应的功能。

这个方法内要避免引入任何副作用(side effect)或者订阅(subscription)。对于这些使用情况,使用componentDidMount()

该方法是可用于服务端渲染(server rendering)的唯一的生命周期方法。

componentDidMount()

componentDidMount()

componentDidMount()在一个组件挂载后立即被调用。需要DOM节点的初始化应该发生在这里。如果你需要从远程节点加载数据,这里是发起网络请求的好地方。

该方法也是创建订阅(subscription)的好地方。如果你在该方法里面创建了订阅,不要忘记在componentWillUnmount()中取消订阅。

在该方法中调用setState()会触发一次额外的渲染,但是它会在浏览器更新屏幕之前发生。这就保证了这种情况下尽管render()会被调用两次,用户不会看到中间状态。使用这种模式一定要小心,因为它经常会导致性能问题。但是,这种方法对于一些情况还是必要的,比如模态对话框或者工具提示消息这种你需要测量一个DOM节点,因为渲染之前你需要这个节点的尺寸和位置信息。

componentWillReceiveProps()

componentWillReceiveProps()

componentWillReceiveProps()在一个已经挂载的组件接收到新的属性props信息时被调用。如果你需要根据属性变化相应地更新组件状态(比如要重置状态),你就可以比较this.propsnextProps然后在该方法中使用this.setState()完成(perform)状态变化(state trabsition)。

需要注意即使属性props没有发生变化,React也会调用该方法,所以如果你仅仅想在变化发生时处理变化,需要确保先比较当前this.props和新的属性值nextProps。在父组件引起你的组件重新渲染时,这种情况是可能发生的。

在挂载过程中React不会使用初始属性props调用componentWillReceiveProps()。React仅仅在组件实例的属性props更新时调用该方法。调用this.setState()一般也不会触发调用componentWillReceiveProps()

shouldComponentUpdate()

shouldComponentUpdate()

方法shouldComponentUpdate()用来让React知道一个组件的输出是否要受到其状态state或者属性props当前的变化的影响。缺省行为是在每一个状态变化(every state change)发生时重新渲染,并且大多数情况下,你应该依赖这种缺省行为。

shouldComponentUpdate()在新的属性props或者状态state被接收到后,渲染之前被调用。缺省情况下总是返回true。对于初始渲染该方法不会被调用,forceUpdate()被使用时该方法也不会被调用。

该方法返回false并不会阻止当前组件的子组件的重新渲染(当它们的状态state发生变化时)。

目前,shouldComponentUpdate()返回false时,componentWillUpdate(),render()componentDidUpdate()这三个方法都不会被调用。但是请注意将来React有可能将shouldComponentUpdate()作为提示(hint)而不是严格指令(strict directive)对待,相应地,返回false仍然会导致组件的重新渲染。

如果在做过性能分析之后你确定某个组件很慢,你可以把变成继承自React.PureComponent,该基类使用浅层属性/状态(propsstate)比较实现了shouldComponentUpdate()。如果你很有信心想自己手写该方法,你可以比较this.propsnextProps,比较this.statenextState然后返回false就可以告诉React该更新可以被忽略。

我们不推荐在方法shouldComponentUpdate()中使用深度相等检查或者JSON.stringify(),这些做法效率很低而且损害性能。

componentWillUpdate()

componentWillUpdate(nextProps, nextState)

componentWillUpdate()在新的属性props和状态state接收到,组件渲染前被调用。这个方法可以作为更新发生前做准备的一个机会。对于初始渲染动作,该方法不会被调用。

需要注意该方法中不可以调用this.setState(),而且在该方法返回前,你也不能做任何会触发组件更新的其它事情,比如分发一个Redux action。

如果你想根据props的变化更新state,使用componentWillReceiveProps()

注意 :
如果shouldComponentUpdate()返回falsecomponentWillUpdate()不会被调用。`

 
译注:
在一个更新周期内,一旦shouldComponentUpdate返回true,componentWillUpdate就会被调用。在componentWillUpdate方法内,任何会导致状态变化的this.setState调用都是不允许的,因为该方法componentWillUpdate被严格限制用来只做即将到来的更新的准备工作,而假如你在这里调用了this.setState,该调用会触发另外一个componentWillUpdate,这样就陷入了一个死循环。
该方法比较常见的应用是基于状态变化设置一些变量(不是使用setState这种会导致状态变化的动作),分派一些事件,或者做一些开始动画的准备工作。

componentDidUpdate()

componentDidUpdate(prevProps, prevState)

componentDidUpdate()在组件更新后完成后立即被调用。该方法在初始渲染时不会被调用。

当组件被更新时可以使用该方法作为一个操作DOM的机会。只要你比较了当前属性和之前的属性,这也是一个很好的地方用于网络请求(如果属性没有发生变化,网络请求可能不是必要的)。

注意 :
如果shouldComponentUpdate()返回falsecomponentDidUpdate()不会被调用。

componentWillUnmount()

componentWillUnmount()

componentWillUnmount()会在一个组件被卸载和销毁前被调用。这个方法用于执行一些必要的清理工作,比如关闭定时器,取消网络请求,或者清除在componentDidMount()创建的任何订阅。

componentDidCatch()

componentDidCatch(error, info)

错误边界(Error Boundary)是这样一种React组件,它们捕捉它们子组件树中任何地方发生的Javascript错误,记录这些错误到日志,然后显示一个fallback UI给用户而不是向用户展示一棵垮掉的组件树。错误边界可以捕捉它下面的整棵组件树中发生在渲染期间,生命周期方法中或者构造方法中的错误。

如果一个组件的类定义了该方法,那么该类的组件就变成了一个错误边界。调用它的setState()方法能让你捕捉到其下属子树中未处理的Javascript错误并展示一个fallback UI。错误边界仅仅设计用于从意料之外的错误之中恢复,所以不要尝试将它用于流程控制。

更多详情,请参考 Error Handling in React 16

注意 :
错误边界仅仅捕捉来自其下属子树的组件中的错误。边界组件自身所发生的错误,它自己并不捕捉。

setState()

setState(updater[, callback])

setState()将组件状态的变化添加到队列,然后告诉React该组件及其子组件需要使用更新了的状态重新渲染。这是在事件发生时或者服务端响应时你更新用户界面要用的基本(primary)方法。

可以把setState()想象成一个请求而不是一个马上更新组件的命令。为了更好的性能,React可能会延迟对其的处理,然后一次性批处理好几个组件。React并不确保状态变化被立即执行。

setState()并不总是立即更新组件。它可能批量更新或者延迟更新到稍微晚些时候执行。这种行为会导致在刚刚调用完setState()时读取this.state读不到最新的状态。对于该问题,相应地使用componentDidUpdate或者一个setState回调函数,这两种方法都保证会在更新执行之后触发,从而可以获取最新的状态数据。如果你想基于之前的状态设置新状态,读一下下面关于参数updater的部分。

setState()总会引起重新渲染,除非shouldComponentUpdate()返回false。如果shouldComponentUpdate()中使用了可变对象,并且条件渲染逻辑在这里无法使用,仅在新状态和旧状态不同时调用setState()方法会避免一些不必要的重新渲染。

setState的第一个参数是一个签名如下的函数 :

(prevState, props) => stateChange

prevState是一个指向之前状态的引用。它不能直接修改。相反地,变化应该被表示成基于输入prevStateprops构建的一个新的对象。比如,想象一下我们想增加向状态中的某个值,增量是props.step :

this.setState((prevState, props) => {
  return {counter: prevState.counter + props.step};
});

updater函数参数prevStateprops接收到的值都被确保是最新值。其输出,也就是返回结果会浅层合并到prevState中去形成更新后的state

setState()的第二个参数是一个可选的回调函数,一旦setState()请求的变化被应用和组件被重新渲染后它就会被执行。一般情况下我们推荐使用componentDidUpdate()而不是这种方法处理这种逻辑。

作为可选项,你可能想向setState()的第一个参数传递一个对象而不是一个上述的updater函数,比如 :

setState(stateChange[, callback])

这种方法会将这个对象stageChange浅层合并到新的state。比如,调整一个购物车项的数量 :

this.setState({quantity: 2})

这种形式的setState()也是异步的,同一周期(cycle)中的多个调用可能被批处理到一起。比如,如果你想在同一个周期中尝试增加一个项目的数量多次(2次以上),也就是想产生跟下面等价的结果 :

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

但实际上同一周期中后续的调用会覆盖前面调用的值,最终数量仅仅增加一次,也就是说,上面的预期的实际结果可能如下所示并非符合预期 :

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

更多详情,可以参考 :

forceUpdate()

component.forceUpdate(callback)

缺省情况下,当你的组件的状态state或者属性props发生变化的时候,组件会重新渲染。如果你的render()还依赖于其他数据,那么你可以通过调用方法forceUpdate()告诉React组件需要重新渲染了。

调用forceUpdate()会引起组件上render()方法的调用,而方法shouldComponentUpdate()会被跳过。对forceUpdate()的调用会触发子组件正常的生命周期方法执行,包括每个子组件的shouldComponentUpdate()。React还是会仅在标记发生变化时才更新DOM。

一般情况下应该尽量避免使用forceUpdate(),而应该仅仅使用从render()读取this.propsthis.state的方式。

类属性

defaultProps

defaultProps可以被定义到组件类(译注:是组件类,而非组件实例,注意区分)本身用于设置该类实例的缺省属性。该属性仅用于定义未定义的属性(undefined props),而不应用于明确被设置为null的属性。举例如下 :

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

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

如果props.color没有提供,下面的代码中CustomButton组件实例的props.color属性值会是缺省值blue:

  render() {
    return <CustomButton /> ; // props.color 这里会是缺省值 blue
  }

如果props.color被明确地设置成了null,那它会保持还是null:

  render() {
    return <CustomButton color={null} /> ; // props.color 被明确设置成了null,那么它就是 null而不使用缺省值
  }

displayName

displayName属性字符串用于调试中的消息。通常情况下你不需要显式地设置它,因为他会从定义组件的函数或者类的名称中演化出来一个。但出于调试目的如果你想显示一个不一样的名称,你可以显式地指定displayName。另外当你想创建一个高阶(higher-order)组件,你可以指定displayName。关于displayName,这里有更多的信息:Wrap the Display Name for Easy Debugging

实例属性

props

this.props包含了当前组件调用者所定义的属性。这里有有关属性props的介绍:Components and Props

特别需要值得一提的是,this.props.children是一个特殊的属性,典型地由JSX表达式中多个子标签定义而不是在当前组件标签中定义。(译注:这句翻译可能不够清楚,原文是 In particular, this.props.children is a special prop, typically defined by the child tags in the JSX expression rather than in the tag itself.)

state

state包含了当前组件相关的时刻会变化的那些数据(译注:所以称之为状态)。状态是用户自定义的(user-defined),应该是一个一般(plain) JavaScript对象。

如果某个数据你不会在render()使用它,那它也不应该出现在状态state中。比如,你可以把定时器(timer)的ID直接设置到实例上。

关于状态state,这里有更多信息:State and Lifecycle

永远不要直接改变state对象,因为随后的setState()调用会替换掉你的变更。将this.state对象看成是一个不可变对象。(译注:但是并不是说该对象的内容不可改变,它的内容必须能被改变,如果要改变它,使用React推荐的方法setState())

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值