react 使用的小建议

  • 使用pureRender,setState和Immutable.js来操做state

Immutable 中文意思不可变。html

不能直接修改state的值,要用setState 和Immutablereact

react 官方要求不要直接修改state,好比this.state.name = "suyuan"是错误的写法,应该用this.setState({name, "suyuan"});git

缘由1.其实state并非不可变的,官方是但愿你把他当作不变来用,由于只有setState的时候才会发生消息给react 来re-render,this.state.name="bianhua" 不会引发re-rener;es6

缘由2.原本无论你数据有没有变化, setState就必定会从新渲染,为了提升性能通常会引去pureRender技术(本文其余章节有描述),该技术是进行浅比较(根节点的地址),p1,p2,p3github

 

假如你这样错误的写:typescript

let p1=state.p1;

p1.name = "bianhua";

this.setState({p1:p1});

用了pureRender技术后,react 发现p1没有变化(p1的地址没变,不是新对象),也不会re-render编程

因此你应该这样写redux

let p1=JsFrom(state.p1);

p1.name = "bianhua";

this.setState({p1:p1});

这篇文章描述了immutable数组

https://zhuanlan.zhihu.com/p/20295971?columnSlug=purerenderantd

 

使用PureRenders

Example Mixin 混入类s:

var PureRenderMixin = require('react-addons-pure-render-mixin');
React.createClass({
  mixins:[PureRenderMixin],
  render: function() {
    return <div className={this.props.className}>foo</div>;
  }
});

 

Example using ES6 class syntax:

import PureRenderMixin from 'react-addons-pure-render-mixin';
class FooComponent extends React.Component {
  constructor(props) {
    super(props);
    this.shouldComponentUpdate=PureRenderMixin.shouldComponentUpdate.bind(this);
  }
  render() {
    return <div className={this.props.className}>foo</div>;
  }
}
 

或者用pure-render-decorator 装饰器

import {Component} from 'react';

import pureRender from 'pure-render-decorator';

@pureRender
export default class Test extends Component {
  render() {
    return <div />;
  }
}
 

a. 优化了性能

PureRenderMixin 重写了shouldComponentUpdate,只有在props或者state真正改变的时候才会从新render,这个在react性能上是一个优化,今后之后你能够大胆的setState,而不须要写这样的代码

if (this.state.someVal !== computedVal) { // 判断是否须要setState,由于每次setState都会引发render,无论你的数据是否是真的变化了

    this.setState({someVal: computedVal})

}

 

 

b.有一点要注意,继承PureRenderMixin要求render 必须是纯函数,固然原本react官文就说render should 纯函数,这里跟须要时纯函数,为何?

b.1.单纯react来说,页面和state直接反应,若是render不是纯函数,就会致使页面展现和state对不上号,还有去查询其余关联数据;

b.2.从继承混入类来讲,若是你写了下面这种不纯的代码

render: function () {

    //

    if (this._previousFoo !== this.props.foo) { // <-- IMPURE

        return renderSomethingDifferent();

    }

}

 

依赖了一个其余变量this._previousFoo,就会引入bug;

>原本不用混入类,你setState后就算state不改变,也会render,而后再render过程当中this._previousFoo的数据变化可能致使页面发生变化;

>如今引入混入类,完蛋了,setState后,state数据不变也就不会render了,页面不变了,和你但愿的不同了。

因此render要纯正,除非上面this._previousFoo 你保证永远不变,是个const

 

c 还有个重要的事情要说,我以为过重要了,PureRenderMixin混入类 只会进行浅比较,就是C++里面的指针(地址比较),若是你修改了一个数组的某个item,你实际上是但愿render的,可是PureRenderMixin 认为数组的地址没变,数组也就没变,也就没render;怎么办?

c.1.组件建立新对象--切片 array.silce()

c.2.object建立新对象-- var copy = Object.assign({}, obj);

c.3.react 自带的操做数据的方式 https://facebook.github.io/react/docs/update.html

c.4..第三方库Immutable.js 和 mori

 

这里有个坑,用了purRender有时候无效,好比组件下面包含了子组件的时候,this.props.children 就算数据不变,对象也不是原来的对象的,为了优化某个组件的性能我还特地重写了shouldComponentUpdate,把props.children 排除了,这个多是purRender的原则,看了下源代码彻底没搞明白,因此假如render不纯的话(好比使用了this.name)我估计仍是会重写渲染,有兴趣会试验一下

 

这里插入一句,redux中的mapToState() 作为reducer和Component的桥梁,reducer 在返回newState后虽然确定会执行mapToState,可是mapToState中return出去的数据{xkey:xvalue},若是xvalue的地址没有改变,mapToState关联的Component也不会render;

 

适当的使用context,方便给子组件传变量

父组件给子组件上下文定义个变量,子组件声明这个变量,就可使用;

方便数据传递,不须要经过props一层层塞进去

// ------Component A

class A extends React.Component {

// add the following property

static childContextTypes = {

  user: React.PropTypes.object.isRequired

}

 

// add the following method

  getChildContext() {

    return {

      user: this.props.user  //children 组件可使用this.context.user

    }

  }

 

  render() {

    <div>{this.props.children}</div>

  }

}

 

// -----Component D

class D extends React.Component {

// add the following property

static contextTypes = {

  user: React.PropTypes.object.isRequired

}

 

  render() {

    <div>{this.context.user.name}</div>

  }

}

 

 

或者

function D(props, context) {

  return (

    <div>{this.context.user.name}</div>

  );

}

D.contextTypes = {

  user: React.PropTypes.object.isRequired

}

 

使用propTypes 和defaultProps

class Greeting extends React.Component {

  static propTypes = {
    name: React.PropTypes.string
  }

  static defaultProps = {
  name: "suyuans"
} render() {
return ( <h1>Hello, {this.props.name}</h1> ); } }

 

React 能够帮你检测传入的props是否有误,本身在使用组件时候也会更清晰须要传入什么props

不过要记得在编译线上版本的时候设置环境变量NODE_ENV="production",避免影响线上的性能 

 

减小操做state

全部的编程语言在写代码的过程当中,都但愿是无状态的,纯函数的方式;

React 提供了setState 接口,可是咱们还要是减小他的使用;

若是state使用很差可能致使组件复杂混乱,re-render 失控;

好比在 componentDidMount() or componentDidUpdate()生命周期中使用setState1是控制很差可能发生死循环,2是加入子组件也相似的使用,子子组件等刷新的次数会成2的幂次方增长;

不过使用state是必不可少的,可是必定要封装好state,确保只有本组件可见;

假如父组件须要知道一些关于子组件的state,这就破坏了组件的结构,意味着组件的抽象失败,能够须要对该组件重构

 

集中管理state

在工做中,父组件须要知道子组件的state或者信息是必不可少的,通常咱们把state彻底集中在一个地方(通常最顶层)控制,

父组件经过props向子组件传递信息,

这就是Flux 架构模型:用集合仓库来管理state,用action事件来驱动state的更新,这时候state的存储和操做都是原子性的,任何state的变化都会去从新渲染组件,以达到单向数据流的目的;

意思就是全部组件都依赖props渲染数据,数据源所有来自数据中心state,组件经过 事件、管道、回调、方法、stream来和数据中心通讯。

 

这个看起来有点低效,可是react所倡导的就是 js的速度很快和虚拟dom diff的思想;

纯props的组件库会更好的发挥purRender相关的优点;

 

缺点是 会使得原来一些简单的经过setSate的事情变的麻烦了,可是优势是单向数据流更直观的反应了咱们的应用。

 

 

这种思想就像flux架构,见下图

 

 

一旦数据中心store 数据变动了,他就render组件,组件会向子组件传递变动的数据

说白了,组件就是处理props 到 页面的纯函数,这样的组件也更容易使用和测试, 组件正常的展现,正常触发事件,触发事件后store数据更新正常 就代表组件一切ok。

若是组件之间经过回调函数来操做,组件之间的耦合性就过高,须要知道对方的一些数据、接口、函数,这样抽象就失败了,应该经过action的方式相互通信。

 

尽可能把代码写在render中

尽可能把componentWillReceiveProps or componentWillMount 下面的代码写到render中,

把一些处理props,或者计算setState的处理函数写到render

永远不要担忧js的速度,这样写的好处不少,减小bug并容易发现bug,减小重复代码等

// bad

componentWillMount: function () {

    this.setState({

        computedFoo: compute(this.props.foo)

    });

},

componentWillReceiveProps: function (nextProps) {

    this.setState({

        computedFoo: compute(nextProps.foo)

    });

},

render: function () {

    return React.DOM.div({className: this.state.computedFoo});

}


// better

render: function () {

    var computedFoo = compute(this.props.foo);

    return React.DOM.div({className: computedFoo});

}

 

也能够在render 中计算获取其余的组件,在render 作更多的事情,固然也不要把render搞的太长太大

 

 

MIXIN 或者extend 很是好用

能够用他们来建立复用的功能块

PureRenderMixin  就是覆盖了shouldComponentUpdate() 方法

你可能有疑问了,生命周期componentWillMount之类的继承下来不就遭了,有的我不须要是否是要重写个空的?放心,mixin特地把生命周期排除出去啊,哈哈 机智啊

好比咱们能够把处理state的逻辑放到mixin中,就算只有一个组件只用也ok,这样能够保证组件内部的无状态性,经过mixin 来构建有状态的组件,之后你能够经过修改mixin来更换功能,复用这个组件,mixin这时候有点control层的角色扮演,不太小心的是mixin要被抛弃了,用extend把

 

 

使用类实例的属性

尽管组件应该是以props为参数的纯函数,可是有时候使用实例属性也是明智的。

有时候this.foo比this.props.foo要更合适;要注意的是PureRender 的时候render下不要这样使用,缘由看以前的内容。

若是这个数据不影响页面的呈现,这样用是很是方便的

 

componentWillReceiveProps: function () {

    this._timer = Date.now();

},

onLoadHandler: function () {

    this.trigger("load:time", Date.now() - this._timer);

},

render: function () {

    return React.DOM.img({

        src: this.props.src,

        onLoad: this.onLoadHandler

    });

}

 

上面用一个实例属性来存放开始时候,以计算load时间,这个时间变化后我也不须要页面展现渲染,因此能够放在实例属性中。

一句话,数据变化了,页面不须要刷新变化的,能够做为实例属性

数据变化,页面变化的那就是state了

 

组件通讯

父到子  1.props, 2.ref   

子到父  1.回调函数this.props.callback()

兄弟   1.经过父绕一圈,2.采用第三方消息系统如js-signals: https://github.com/millermedeiros/js-signals

 

一切通讯,若是用了flux或者redux就解决了

 

 

下面是一些js使用建议

1.遵循es6严格模式

2.声明变量的优先级 const、let

3.箭头函数代替繁杂的bind

4.能够引用typescript减小bug,固然用了严格模式也足够了

 

推荐个组件库 antd

推荐使用redux(control、modal层) 管理react(view层s)

 

本文参考了

React建议:http://aeflash.com/2015-02/react-tips-and-best-practices.html

immutable使用:

https://zhuanlan.zhihu.com/p/20295971?columnSlug=purerender

https://www.w3ctech.com/topic/1595

相关文章
相关标签/搜索