標籤:
這是 Steven Luscher 寫的一篇關於 React 的文章,Steven Luscher 擅長使用 React 和 GraphQL 構建應用。
原文地址:http://babeljs.io/blog/2015/06/07/react-on-es6-plus/
當重新設計 Instagram Web 的時候,使用了一些 ES6+ 的特性來編寫 React 組件。在這裡簡要的說一下這些語言新特性對 React 應用的開發有什麼影響,這些 ES6+ 特性使得 React 開發更簡單更有趣。
類
迄今為止,最能體現我們使用 ES6+ 來編寫 React 組件的就是我們選擇使用類定義文法。替代了使用 React.createClass
方法來定義一個組件,我們可以定義一個 bonafide ES6 類來擴充 React.Component:
class Photo extends React.Component { render() { return <img alt={this.props.caption} src={this.props.src} />; }}
現在,你就會發現一個微妙的差異 —— 當使用定義類的時候文法更簡潔:
// The ES5 wayvar Photo = React.createClass({ handleDoubleTap: function(e) { … }, render: function() { … },});
// The ES6+ wayclass Photo extends React.Component { handleDoubleTap(e) { … } render() { … }}
值得關注的是,我們去掉了兩個括弧和一個分號,每個方法聲明我們省略了一個冒號,一個關鍵字和一個分號。
當使用新的類定義時,所有的生命週期方法至少有一個是符合你期望的。類的 constructor 現在假設 role 之前是通過 componentWillMount 填充的:
// The ES5 wayvar EmbedModal = React.createClass({ componentWillMount: function() { … },});
// The ES6+ wayclass EmbedModal extends React.Component { constructor(props) { super(props); // Operations usually carried out in componentWillMount go here }}
屬性初始化程式
在 ES6+ 類的世界裡,prop types 和 defaults live 在類自身作為靜態屬性。這些,在組件的初始化狀態也是一樣的,可以使用 ES7 property initializers 定義:
// The ES5 wayvar Video = React.createClass({ getDefaultProps: function() { return { autoPlay: false, maxLoops: 10, }; }, getInitialState: function() { return { loopsRemaining: this.props.maxLoops, }; }, propTypes: { autoPlay: React.PropTypes.bool.isRequired, maxLoops: React.PropTypes.number.isRequired, posterFrameSrc: React.PropTypes.string.isRequired, videoSrc: React.PropTypes.string.isRequired, },});
// The ES6+ wayclass Video extends React.Component { static defaultProps = { autoPlay: false, maxLoops: 10, } static propTypes = { autoPlay: React.PropTypes.bool.isRequired, maxLoops: React.PropTypes.number.isRequired, posterFrameSrc: React.PropTypes.string.isRequired, videoSrc: React.PropTypes.string.isRequired, } state = { loopsRemaining: this.props.maxLoops, }}
ES7 屬性初始化程式操作內部類的 constructor,this
指向 construction 的類執行個體,所以初始化狀態可以依賴於 this.props。值得關注的是,我們不再定義 prop 預設值和使用 getter 函數初始化狀態物件。
Arrow 函數
React.createClass
方法用來在你的組件執行個體方法中執行一些額外的綁定工作,為了確保 this
關鍵字會指向組件執行個體:
// Autobinding, brought to you by React.createClassvar PostInfo = React.createClass({ handleOptionsButtonClick: function(e) { // Here, ‘this‘ refers to the component instance. this.setState({showOptionsModal: true}); },});
自從我們不參與 React.createClass
方法,而是使用 ES6+ 類文法定義組件,看似需要手動綁定執行個體方法:
// Manually bind, wherever you need toclass PostInfo extends React.Component { constructor(props) { super(props); // Manually bind this method to the component instance... this.handleOptionsButtonClick = this.handleOptionsButtonClick.bind(this); } handleOptionsButtonClick(e) { // ...to ensure that ‘this‘ refers to the component instance here. this.setState({showOptionsModal: true}); }}
幸運的是,通過綁定兩個 ES6+ 特性 – arrow functions 和屬性初始化程式 – 可以選擇綁定組件執行個體:
class PostInfo extends React.Component { handleOptionsButtonClick = (e) => { this.setState({showOptionsModal: true}); }}
ES6 的 arrow 函數體分享相同的詞 this,用這來
圍繞他們的代碼,這些可以達到我們預期的結果,也是 ES7 屬性初始化程式在域內的方式。 Peek under the hood 來看看為什麼能實現。
動態屬性名稱 & 模板字串
其中一個對象常量增強是可以分配到一個派生屬性名稱。我們最初可能會像下面這樣設定一些狀態:
var Form = React.createClass({ onChange: function(inputName, e) { var stateToSet = {}; stateToSet[inputName + ‘Value‘] = e.target.value; this.setState(stateToSet); },});
現在,我們有能力構造通過一個運行時 JavaScript 運算式確定屬性名稱的對象。這裡,我們使用了一個模板字串來確定哪個屬性設定狀態:
class Form extends React.Component { onChange(inputName, e) { this.setState({ [`${inputName}Value`]: e.target.value, }); }}
解構 & 傳播屬性
通常在編寫組件的時候,我們可能想把大部分父組件的 props 傳遞給子組件,但不是所有。結合 ES6+ 解構和 JSX 傳播屬性,這個不需要多餘的部分就能實現:
class AutoloadingPostsGrid extends React.Component { render() { var { className, ...others, // contains all properties of this.props except for className } = this.props; return ( <div className={className}> <PostsGrid {...others} /> <button onClick={this.handleLoadMoreClick}>Load more</button> </div> ); }}
我們可以結合 JSX 傳播屬性和常規屬性,利用一個簡單的優先原則實現 overrides 和 defaults。這個元素會要求 className
“override” 甚至是在 this.props 存在 className
屬性:
<div {...this.props} className="override"> … </div>
這個元素常規來說需要 className
“base” ,除非 this.props 有 className
屬性覆蓋:
<div className="base" {...this.props}> … </div>
希望大家能享受 ES6+ 語言特性給 React 開發帶來的一些便利。
結合 ES6+ 開發 React 組件