React中的组件

在 React 中,万物皆组件。

Component

这是 React 中最常见、最通用的组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// es6
class MyComponent extends Component {
construcor(props) {
super(props);
this.state = {};
}
render() {
return <div>I am a Component, you can use props.</div>;
}
}
// es5 不推荐
const MyComponent = React.createClass({
getInitialState: function () {
return {};
},
render() {
return <div>I am a Component, you can use props.</div>;
},
});

PureComponent

我们知道组件在 props 或者 state 发生改变时,会触发组件的 shouldComponentUpdate ,然后根据 shouldComponentUpdate 的返回值确定是否触发 re-render。而事实上 PureComponent 继承了 Component,然后在 shouldComponentUpdate 是做了以下处理:

1
2
3
4
5
if (type.prototype && type.prototype.isPureReactComponent) {
return (
!shallowEqual(oldProps, newProps) || !shallowEqual(oldState, newState)
);
}

因此,PureComponent 和 Component 的区别就是它在 shouldComponentUpdate 时默认判断新旧属性和状态是否相同,如果没有改变默认返回 false。当然我们可以看到,新旧属性和状态的比较都是浅比较。

相对 Component 优点:

  1. 在 shouldComponentUpdate 生命周期做了优化会自动 shadow diff 组件的 state 和 props,结合 immutable 数据就可以很好地去做更新判断;
  2. 隔离了父组件与子组件的状态变化;

相对 Component 缺点:

  1. shouldComponentUpdate 中的 shadow diff 同样消耗性能;
  2. 需要确保组件渲染仅取决于 props 与 state ;

通过上面的比较,相比于 Component ,PureComponent 有性能上的更大提升,那么我们可不可以全部使用 PureComponent 来提升性能呢?答案当然是否定的,如果是这样那么 React 官方早应该使用 PureComponent 作为其默认组件了。原因如下:

  1. 我们应该避免过早优化,当在应用出现性能瓶颈的时候才需要去排查与解决这部分的渲染;
  2. 在 shouldComponentUpdate 中先置进行新旧属性与状态的浅比较同样是对于性能上的消耗,而其带来的优化效果与性能消耗还需结合实际情况进行抉择;
  3. PureComponent 在 shouldComponentUpdate 所做的也仅是浅层的对象比较,在属性/状态层级结构较深较复杂的情况下容易出现深层 bug,当然如果引入了 immutable 数据那么这里的风险将会大大减小;
  4. 在我们真正遇到性能瓶颈时,很多时候的处理并不仅仅是比较属性/状态是否改变,因此 PureComponent 在这种情况下优势也不大。

函数式组件

React 可以通过函数定义一个组件,称之为函数式组件。由于函数式组件不存在自身的状态,并且没有普通组件的生命周期方法,同时函数的写法决定了它的渲染只由它的属性来决定,因此对于简单的通用性组件是比较适合的。

1
2
3
const MyComponent = ({ ...props }) => (
<div>I am a functional Component, you can use props.</div>
);

相对 Component 优点:

  1. 简化代码、专注于 render;
  2. 组件不需要被实例化,无生命周期,提升性能;
  3. 输出(渲染)只取决于输入(属性),无副作用;
  4. 视图和数据的解耦分离;

相对 Component 缺点:

  1. 无法使用 ref;
  2. 无生命周期方法;
  3. 无法控制组件的重渲染,因为无法使用 shouldComponentUpdate 方法,当组件接受到新的属性时则会重渲染;

Smart 组件与 Dumb 组件

当应用的视图层与数据层解耦的情况下,比如结合 Redux 或者 Mobx 等状态管理库,那么在一个应用中组件又分为 Smart 组件与 Dumb 组件。

Smart 组件

Smart 组件又称为 容器组件,它负责处理应用的数据以及业务逻辑,同时将状态数据与操作函数作为属性传递给子组件;
一般而言它仅维护很少的 DOM,其所有的 DOM 也仅是作为布局等作用。

Dumb 组件

Dumb 组件又称为 木偶组件,它负责展示作用以及响应用户交互,它一般是无状态的(在如 Modal 等类组件中可能会维护少量自身状态);
一般而言 Dumb 组件会拆分为一个个可复用、功能单一的组件;
因此 Dumb 组件使用函数式组件定义,当其需要对重渲染进行优化时则可以使用 PureComponent。

所以 Smart 组件更多关注与数据以及业务逻辑,而 Dumb 组件与数据和业务解耦,主要复杂 UI 层面的展示与交互。

高阶组件

高阶组件(higher-order-components)是 react 中对组件逻辑进行重用的高级技术。但高阶组件本身并不是 React API。它只是一种模式,这种模式是由 react 自身的组合性质必然产生的。

这里需要明确一点:高阶组件并不是一个组件类,它是一个函数,接收一个组件并返回一个新组件。高阶组件(HOC)是一种修饰者模式,它对原有组件进行改造并生成新的组件,对组件代码进行的复用。

[越努力,越幸运!]