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
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;
父組件給子組件上下文定義個變量,子組件聲明這個變量,就可使用;
方便數據傳遞,不須要經過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 }
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"
,避免影響線上的性能
全部的編程語言在寫代碼的過程當中,都但願是無狀態的,純函數的方式;
React 提供了setState 接口,可是咱們還要是減小他的使用;
若是state使用很差可能致使組件複雜混亂,re-render 失控;
好比在 componentDidMount()
or componentDidUpdate()
生命週期中使用
setState
,
1
是控制很差可能發生死循環,
2
是加入子組件也相似的使用,子子組件等刷新的次數會成
2
的冪次方增長;
不過使用
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的方式相互通信。
儘可能把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搞的太長太大
能夠用他們來建立複用的功能塊
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就解決了
1.遵循es6嚴格模式
2.聲明變量的優先級 const、let
3.箭頭函數代替繁雜的bind
4.能夠引用typescript減小bug,固然用了嚴格模式也足夠了
本文參考了
React建議:http://aeflash.com/2015-02/react-tips-and-best-practices.html
immutable使用:
https://zhuanlan.zhihu.com/p/20295971?columnSlug=purerender