使用React咱們首先要知道如何傳遞數據,組件如何溝通,才能展現咱們想要的數據。下面的列子都是使用ES6語法,不懂的同窗須要先學習ES6語法。node
React是單向數據流,從父節點傳遞到子節點(經過props
)。若是頂層的某個props
改變了,React會重渲染全部的子節點(未作性能優化)。嚴格意義上React只提供,也強烈建議使用這種數據交流方式。react
props
是property的縮寫,能夠理解爲HTML標籤的attribute。請把props
當作只讀的(不可使用this.props
直接修改props),props
是用於整個組件樹中傳遞數據和配置。在當前組件訪問props
,使用this.props
。在什麼狀況下可使用props
,請看組件生命週期git
class Component { constructor(props){ super(props); } render(){ return ( <div title={this.props.title}></div> ) } } <Component title="test"/>//調用title就傳進去了
PropsTypes
是React中用來定義props
的類型,不符合定義好的類型會報錯。建議可複用組件要使用prop驗證!接着上面的列子設置PropsTypes
以下:github
class Component { ... } Component.PropsType = { title: React.PropTypes.string, }
React.PropTypes
提供不少驗證器 (validator) 來驗證傳入數據的有效性。官方定義的驗證器以下,不是使用ES6語法。redux
React.createClass({ propTypes: { // 能夠聲明 prop 爲指定的 JS 基本類型。默認 // 狀況下,這些 prop 都是可傳可不傳的。 optionalArray: React.PropTypes.array, optionalBool: React.PropTypes.bool, optionalFunc: React.PropTypes.func, optionalNumber: React.PropTypes.number, optionalObject: React.PropTypes.object, optionalString: React.PropTypes.string, optionalSymbol: React.PropTypes.symbol, // 全部能夠被渲染的對象:數字, // 字符串,DOM 元素或包含這些類型的數組(or fragment) 。 optionalNode: React.PropTypes.node, // React 元素 optionalElement: React.PropTypes.element, // 你一樣能夠斷言一個 prop 是一個類的實例。 // 用 JS 的 instanceof 操做符聲明 prop 爲類的實例。 optionalMessage: React.PropTypes.instanceOf(Message), // 你能夠用 enum 的方式 // 確保你的 prop 被限定爲指定值。 optionalEnum: React.PropTypes.oneOf(['News', 'Photos']), // 指定的多個對象類型中的一個 optionalUnion: React.PropTypes.oneOfType([ React.PropTypes.string, React.PropTypes.number, React.PropTypes.instanceOf(Message) ]), // 指定類型組成的數組 optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number), // 指定類型的屬性構成的對象 optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number), // 特定形狀參數的對象 optionalObjectWithShape: React.PropTypes.shape({ color: React.PropTypes.string, fontSize: React.PropTypes.number }), // 你能夠在任意東西后面加上 `isRequired` // 來確保 若是 prop 沒有提供 就會顯示一個警告。 requiredFunc: React.PropTypes.func.isRequired, // 不可空的任意類型 requiredAny: React.PropTypes.any.isRequired, // 你能夠自定義一個驗證器。若是驗證失敗須要返回一個 Error 對象。 // 不要直接使用 `console.warn` 或拋異常, // 由於這在 `oneOfType` 裏不起做用。 customProp: function(props, propName, componentName) { if (!/matchme/.test(props[propName])) { return new Error('Validation failed!'); } } }, /* ... */ });
如何設置組件默認的props
?segmentfault
//React提供的crateClass建立方式 var Component = React.createClass({ getDefaultProps(){ return { //這裏設置defaultProps } } }) //ES6 class Component { ... } Component.defaultProps = {} //ES7 stage-0 class Component { static defaultProps = { } ... }
每一個組件都有屬於本身的state
,state
和props
的區別在於前者之只存在於組件內部,只能從當前組件調用this.setState
修改state值(不能夠直接修改this.state
)。通常咱們更新子組件都是經過改變state
值,更新新子組件的props
值從而達到更新。數組
那如何設置默認state?性能優化
//React提供的crateClass建立方式 var Component = React.createClass({ getInitialState(){ return { //這裏設置初始state值 } } }) //ES6 && ES7 class Component { constructor(){ this.state = {}//在ES6中的構造函數中初始化,能夠之直接賦值,在其餘方法中,只能使用this.setState } ... }
儘量使用props
當作數據源,state
用來存放狀態值(簡單的數據),如複選框、下拉菜單等。架構
組件溝通由於React的單向數據流方式會有所限制,下面述說組件之間的溝通方式。框架
這種方式是最多見的,也是最簡單的。
父組件更新組件狀態
父組件更新子組件狀態,經過傳遞props
,就能夠了。
子組件更新父組件狀態
這種狀況須要父組件傳遞迴調函數給子組件,子組件調用觸發便可。
代碼示例:
class Child extends React.Component{ constructor(props){ super(props); this.state = {} } render(){ return ( <div> {this.props.text} <br /> <button onClick={this.props.refreshParent}> 更新父組件 </button> </div> ) } } class Parent extends React.Component{ constructor(props){ super(props); this.state = {} } refreshChild(){ return (e)=>{ this.setState({ childText: "父組件溝通子組件成功", }) } } refreshParent(){ this.setState({ parentText: "子組件溝通父組件成功", }) } render(){ return ( <div> <h1>父子組件溝通</h1> <button onClick={this.refreshChild()} > 更新子組件 </button> <Child text={this.state.childText || "子組件未更新"} refreshParent={this.refreshParent.bind(this)} /> {this.state.parentText || "父組件未更新"} </div> ) } }
codepen例子React組件之父子組件溝通 。
當兩個組件有相同的父組件時,就稱爲兄弟組件(堂兄也算的)。按照React單向數據流方式,咱們須要藉助父組件進行傳遞,經過父組件回調函數改變兄弟組件的props
。
經過props
傳遞父組件回調函數。
class Brother1 extends React.Component{ constructor(props){ super(props); this.state = {} } render(){ return ( <div> <button onClick={this.props.refresh}> 更新兄弟組件 </button> </div> ) } } class Brother2 extends React.Component{ constructor(props){ super(props); this.state = {} } render(){ return ( <div> {this.props.text || "兄弟組件未更新"} </div> ) } } class Parent extends React.Component{ constructor(props){ super(props); this.state = {} } refresh(){ return (e)=>{ this.setState({ text: "兄弟組件溝通成功", }) } } render(){ return ( <div> <h2>兄弟組件溝通</h2> <Brother1 refresh={this.refresh()}/> <Brother2 text={this.state.text}/> </div> ) } }
codepen例子:React組件之兄弟組件溝通。
可是若是組件層次太深(以下圖),上面的兄弟組件溝通方式就效率低了(不建議組件層次太深)。
React提供了一種上下文方式(挺方便的),可讓子組件直接訪問祖先的數據或函數,無需從祖先組件一層層地傳遞數據到子組件中。
class Brother1 extends React.Component{ constructor(props){ super(props); this.state = {} } render(){ return ( <div> <button onClick={this.context.refresh}> 更新兄弟組件 </button> </div> ) } } Brother1.contextTypes = { refresh: React.PropTypes.any } class Brother2 extends React.Component{ constructor(props){ super(props); this.state = {} } render(){ return ( <div> {this.context.text || "兄弟組件未更新"} </div> ) } } Brother2.contextTypes = { text: React.PropTypes.any } class Parent extends React.Component{ constructor(props){ super(props); this.state = {} } getChildContext(){ return { refresh: this.refresh(), text: this.state.text, } } refresh(){ return (e)=>{ this.setState({ text: "兄弟組件溝通成功", }) } } render(){ return ( <div> <h2>兄弟組件溝通</h2> <Brother1 /> <Brother2 text={this.state.text}/> </div> ) } } Parent.childContextTypes = { refresh: React.PropTypes.any, text: React.PropTypes.any, }
codepen例子:React組件之兄弟組件溝通2
For communication between two components that don't have a parent-child relationship, you can set up your own global event system. Subscribe to events in
componentDidMount()
, unsubscribe incomponentWillUnmount()
, and callsetState()
when you receive an event.Flux pattern is one of the possible ways to arrange this.
官網中提到可使用全局事件來進行組件間的通訊,官網推薦Flux(Facebook官方出的),還有Relay、Redux、trandux等第三方類庫。這些框架思想都一致,都是統一管理組件state變化狀況,達到數據可控目的。本人使用了Redux,建議要會其中一種。對於EventEmitter或PostalJS這類的第三方庫是不建議使用的,這類全局事件框架並無統一管理組件數據變化,用多了會致使數據流不可控。
這裏就不細說,請選擇其中一種類庫,深刻學習下。
簡單的組件交流咱們可使用上面非全局事件的簡單方式,可是當項目複雜,組件間層次愈來愈深,上面的交流方式就不太合適(固然仍是要用到的,簡單的交流)。強烈建議使用Flux、Relay、Redux、trandux等類庫其中一種,這些類庫不僅適合React,像Angular等均可以使用。