我们知道,当组件的props或者state发生变化的时候:React会对组件当前的Props和State分别与nextProps和nextState进行比较,当发现变化时,就会对当前组件以及子组件进行重新渲染,否则就不渲染。有时候为了避免组件进行不必要的重新渲染,我们通过定义shouldComponentUpdate来优化性能。例如如下代码:

class CounterButton extends React.Component {
constructor(props) {
super(props);
this.state = {count: 1};
} shouldComponentUpdate(nextProps, nextState) {
if (this.props.color !== nextProps.color) {
return true;
}
if (this.state.count !== nextState.count) {
return true;
}
return false;
} render() {
return (
<button
color={this.props.color}
onClick={() => this.setState(state => ({count: state.count + 1}))}>
Count: {this.state.count}
</button>
);
}
}

shouldComponentUpdate通过判断props.colorstate.count是否发生变化来决定需不需要重新渲染组件,当然有时候这种简单的判断,显得有些多余和样板化,于是React就提供了PureComponent来自动帮我们做这件事,这样就不需要手动来写shouldComponentUpdate了:

class CounterButton extends React.PureComponent {
constructor(props) {
super(props);
this.state = {count: 1};
} render() {
return (
<button
color={this.props.color}
onClick={() => this.setState(state => ({count: state.count + 1}))}>
Count: {this.state.count}
</button>
);
}
}

大多数情况下, 我们使用PureComponent能够简化我们的代码,并且提高性能,但是PureComponent的自动为我们添加的shouldComponentUpate函数,只是对props和state进行浅比较(shadow comparison),当props或者state本身是嵌套对象或数组等时,浅比较并不能得到预期的结果,这会导致实际的props和state发生了变化,但组件却没有更新的问题,例如下面代码有一个ListOfWords组件来将单词数组拼接成逗号分隔的句子,它有一个父组件WordAdder让你点击按钮为单词数组添加单词,但他并不能正常工作:

class ListOfWords extends React.PureComponent {
render() {
return <div>{this.props.words.join(',')}</div>;
}
} class WordAdder extends React.Component {
constructor(props) {
super(props);
this.state = {
words: ['marklar']
};
this.handleClick = this.handleClick.bind(this);
} handleClick() {
// 这个地方导致了bug
const words = this.state.words;
words.push('marklar');
this.setState({words: words});
} render() {
return (
<div>
<button onClick={this.handleClick} />
<ListOfWords words={this.state.words} />
</div>
);
}
}

这种情况下,PureComponent只会对this.props.words进行一次浅比较,虽然数组里面新增了元素,但是this.props.words与nextProps.words指向的仍是同一个数组,因此this.props.words !== nextProps.words 返回的便是flase,从而导致ListOfWords组件没有重新渲染,笔者之前就因为对此不太了解,而随意使用PureComponent,导致state发生变化,而视图就是不更新,调了好久找不到原因~。

最简单避免上述情况的方式,就是避免使用可变对象作为props和state,取而代之的是每次返回一个全新的对象,如下通过concat来返回新的数组:

handleClick() {
this.setState(prevState => ({
words: prevState.words.concat(['marklar'])
}));
}

你可以考虑使用Immutable.js来创建不可变对象,通过它来简化对象比较,提高性能。
这里还要提到的一点是虽然这里虽然使用了Pure这个词,但是PureComponent并不是纯的,因为对于纯的函数或组件应该是没有内部状态,对于stateless component更符合纯的定义,不了解纯函数的同学,可以参见这篇文章

react 创建组件 (三)PureComponet的更多相关文章

  1. react创建组件的几种方式及其区别

    react创建组件有如下几种方式 ①.函数式定义的无状态组件 ②.es5原生方式React.createClass定义的组件   ③.es6形式的extends React.Component定义的组 ...

  2. React创建组件的三种方式及其区别

    内容转载于http://www.cnblogs.com/wonyun/p/5930333.html React推出后,出于不同的原因先后出现三种定义react组件的方式,殊途同归; 具体的三种方式: ...

  3. React创建组件的三种方式比较

    推荐文章: https://www.cnblogs.com/wonyun/p/5930333.html 创建组件的方式主要有: 1.function 方式 2.class App extends Re ...

  4. React创建组件的三种方式比较和入门实例

    推荐文章: https://www.cnblogs.com/wonyun/p/5930333.html 创建组件的方式主要有: 1.function 方式 2.class App extends Re ...

  5. React创建组件的不同方式(ES5 & ES6)

    一. 首先缕清楚React.createElement.React.createClass.React.Component之间的关系 1. React.createElement(HTML eleme ...

  6. react 创建组件 (四)Stateless Functional Component

    上面我们提到的创建组件的方式,都是用来创建包含状态和用户交互的复杂组件,当组件本身只是用来展示,所有数据都是通过props传入的时候,我们便可以使用Stateless Functional Compo ...

  7. react 创建组件 (二)component

    因为ES6对类和继承有语法级别的支持,所以用ES6创建组件的方式更加优雅,下面是示例: import React from 'react'; class Greeting extends React. ...

  8. react 创建组件 (一)createClass

    如果你还没有使用ES6语法,那么定义组件,只能使用React.createClass这个helper来创建组件,下面是一段示例: var React = require("react&quo ...

  9. React创建组件的方法,组件的props属性、state属性的用法和特点,父子组件传值,兄弟组件传值

    创建组件的方法,组件的props属性.state属性的用法和特点,父子组件传值,兄弟组件传值 1.react组件 1.1.创建组件的方法 1.1.1.函数组件 定义一个组件最简单的方式是使用JavaS ...

  10. 四、React创建组件、 JSX使用、绑定数据、引用图片方式、数组(列表)循环输出

    接:https://www.cnblogs.com/chenxi188/p/11702799.html 用上节建好的my-app项目: my-app/ README.md node_modules/ ...

随机推荐

  1. python--类的约束, 异常处理, MD5, 日志处理

    一 . 类的约束 1. 写一个父类,父类中的某个方法要抛出一个异常 NotImplementedError class Base: # 对子类进行了约束. 必须重写该方法 # 以后上班了. 拿到公司代 ...

  2. C/C++编程之内存管理

    内存分配方式 内存分配方式一共有三种: (1)从静态存储区域分配: 内存在程序编译的时候就已经分配好,这块内存在程序的整个运行期间都存在,例如,全局变量,静态变量. (2)在栈上创建: 在执行函数时, ...

  3. Spring,Mybatis,Springmvc框架整合项目(第一部分)

    一.说在前面的话 本篇博文实现一个注册登录小项目,使用spring,mybatis,springmvc框架进行整合,我们创建的是一个maven工程,主要是方便jar包版本的管理.项目使用eclispe ...

  4. js--如何判别 null undefined

    收集资料如下判断: 1.判断undefined: ? 1 2 3 4 var tmp = undefined; if (typeof(tmp) == "undefined"){ a ...

  5. Wp检查手机网络状态

    /// <summary> /// 检查网络状态 /// </summary> private void CheckNetworkState() { if (DeviceNet ...

  6. [android 应用开发]android 分层

    1 应用层, 2 应用框架层(框架是所有开发人员共同使用和遵守的约定) 3 系统运行库层 4 linux内核层

  7. n&(n-1)的用途

    最近做LeetCode上面的题目,发现很多题目都用到了n&(n-1).感觉真是神通广大,下面就目前所看到的一些用途总结一下: 1,求一个int类型数是否为2的幂 当n=4时,二进制为:0100 ...

  8. 【Luogu】P3381最小费用最大流模板(SPFA找增广路)

    题目链接 哈  学会最小费用最大流啦 思路是这样. 首先我们有一个贪心策略.如果我们每次找到单位费用和最短的一条增广路,那么显然我们可以把这条路添加到已有的流量里去——不管这条路的流量是多大,反正它能 ...

  9. BZOJ 4566 [Haoi2016]找相同字符 ——广义后缀自动机

    建立广义后缀自动机. 然后统计子树中的siz,需要分开统计 然后对(l[i]-l[fa[i]])*siz[i][0]*siz[i][1]求和即可. #include <cstdio> #i ...

  10. BZOJ 2882 工艺 ——后缀自动机 最小表示法

    先说后缀自动机的做法. 直接把S串复制一遍成SS,然后建立后缀自动机,go边相当于在当前字符的后面插入,而son边可以看作在字符串前面加一个字符. 所以贪心的走字典序最小的边即可,而且根据后缀自动机的 ...