原文:react-patternshtml
class definitionreact
constructorgit
event handlersgithub
'component' lifecycleajax
gettersnpm
renderjson
defaultProps數組
proptypes瀏覽器
class Person extends React.Component { constructor (props) { super(props); this.state = { smiling: false }; this.handleClick = () => { this.setState({smiling: !this.state.smiling}); }; } componentWillMount () { // add event listeners (Flux Store, WebSocket, document, etc.) }, componentDidMount () { // React.getDOMNode() }, componentWillUnmount () { // remove event listeners (Flux Store, WebSocket, document, etc.) }, get smilingMessage () { return (this.state.smiling) ? "is smiling" : ""; } render () { return ( <div onClick={this.handleClick}> {this.props.name} {this.smilingMessage} </div> ); }, } Person.defaultProps = { name: 'Guest' }; Person.propTypes = { name: React.PropTypes.string };
當有2個以上屬性時,就換行顯示緩存
// bad <Person firstName="Michael" /> // good <Person firstName="Michael" />
// bad <Person firstName="Michael" lastName="Chan" occupation="Designer" favoriteFood="Drunken Noodles" /> // good <Person firstName="Michael" lastName="Chan" occupation="Designer" favoriteFood="Drunken Noodles" />
使用getters方法代替定義依賴屬性
// bad firstAndLastName () { return `${this.props.firstName} ${this.props.lastname}`; } // good get fullName () { return `${this.props.firstName} ${this.props.lastname}`; }
使用getters方法代替定義依賴狀態,注意爲了提升可讀性須要在命名時加上一個動詞前綴。
// bad happyAndKnowsIt () { return this.state.happy && this.state.knowsIt; }
// good get isHappyAndKnowsIt () { return this.state.happy && this.state.knowsIt; }
這些方法必須返回boolean
類型
保證渲染邏輯都寫在render
方法裏
// bad renderSmilingStatement () { return <strong>{(this.state.isSmiling) ? " is smiling." : ""}</strong>; }, render () { return <div>{this.props.name}{this.renderSmilingStatement()}</div>; }
// good render () { return ( <div> {this.props.name} {(this.state.smiling) ? <span>is smiling</span> : null } </div> ); }
用定義的組件組成視圖。不要建立混雜着佈局和功能的一次性組件
// bad class PeopleWrappedInBSRow extends React.Component { render () { return ( <div className="row"> <People people={this.state.people} /> </div> ); } }
// good class BSRow extends React.Component { render () { return <div className="row">{this.props.children}</div>; } } class SomeView extends React.Component { render () { return ( <BSRow> <People people={this.state.people} /> </BSRow> ); } }
容器組件負責獲取數據並交付給相應的子組件渲染,僅此而已。— Jason Bonta
// bad // CommentList.js class CommentList extends React.Component { getInitialState () { return { comments: [] }; } componentDidMount () { $.ajax({ url: "/my-comments.json", dataType: 'json', success: function(comments) { this.setState({comments: comments}); }.bind(this) }); } render () { return ( <ul> {this.state.comments.map(({body, author}) => { return <li>{body}—{author}</li>; })} </ul> ); } }
//good // CommentList.js class CommentList extends React.Component { render() { return ( <ul> {this.props.comments.map(({body, author}) => { return <li>{body}—{author}</li>; })} </ul> ); } } // CommentListContainer.js class CommentListContainer extends React.Component { getInitialState () { return { comments: [] } } componentDidMount () { $.ajax({ url: "/my-comments.json", dataType: 'json', success: function(comments) { this.setState({comments: comments}); }.bind(this) }); } render () { return <CommentList comments={this.state.comments} />; } }
相關連接:
Container Components
React.js Conf 2015 - Making your app fast with high-performance components
render
中緩存狀態不要在render
中緩存狀態
// bad render () { let name = `Mrs. ${this.props.name}`; return <div>{name}</div>; } // good render () { return <div>{`Mrs. ${this.props.name}`}</div>; }
// best get fancyName () { return `Mrs. ${this.props.name}`; } render () { return <div>{this.fancyName}</div>; }
這裏多半是出於代碼風格的考慮,不過仍是保持比較好,我懷疑也可能跟性能有關。
不要把複合條件判斷放在render
裏。
// bad render () { return <div>{if (this.state.happy && this.state.knowsIt) { return "Clapping hands" }</div>; }
// better get isTotesHappy() { return this.state.happy && this.state.knowsIt; }, render() { return <div>{(this.isTotesHappy) && "Clapping hands"}</div>; }
這裏最好的解決方案是使用容器組件來管理你的狀態而後在經過屬性(props)往下層傳遞。
不要去檢查是否存在某個prop
值,快使用defaultProps
。
// bad render () { if (this.props.person) { return <div>{this.props.person.firstName}</div>; } else { return null; } }
// good class MyComponent extends React.Component { render() { return <div>{this.props.person.firstName}</div>; } } MyComponent.defaultProps = { person: { firstName: 'Guest' } };
當你的值是對象或者數組時,使用 PropTypes.shape聲明嵌套數據的預期類型。
不要經過props值去設置state,除非明顯是個初始值。
// bad getInitialState () { return { items: this.props.items }; }
// good getInitialState () { return { items: this.props.initialItems }; }
詳細請閱讀官網的Props in getInitialState Is an Anti-Pattern
// bad punchABadger () { /*...*/ }, render () { return <div onClick={this.punchABadger} />; }
// good handleClick () { /*...*/ }, render () { return <div onClick={this.handleClick} />; }
處理方法的命名必須:
第一個單詞爲handle
最後一個單詞爲要響應的事件(好比Click,Change)
如今時態
若是爲了不命名衝突,你能夠在handle和事件名中間加入其餘信息。好比,你能夠定義handleNameChange 和handleAgeChange來區分onChange的不一樣響應處理。不過當你這樣作的時候,你要問問本身是否須要一個新的組件了。
可使用自定義事件替代預設的事件名。
class Owner extends React.Component { handleDelete () { // handle Ownee's onDelete event } render () { return <Ownee onDelete={this.handleDelete} />; } } class Ownee extends React.Component { render () { return <div onChange={this.props.onDelete} />; } } Ownee.propTypes = { onDelete: React.PropTypes.func.isRequired };
使用PropTypes能夠預先定義屬性的類型,能夠在以後得到一些有意義的警告信息。
MyValidatedComponent.propTypes = { name: React.PropTypes.string };
MyValidatedComponent
的name
屬性值若是不是string
類型的話, 會輸出警告。
<Person name=1337 /> // Warning: Invalid prop `name` of type `number` supplied to `MyValidatedComponent`, expected `string`.
在這裏也能夠設置屬性是不是必須存在的。
MyValidatedComponent.propTypes = { name: React.PropTypes.string.isRequired }
這個組件會驗證是否存在name
屬性。
<Person /> // Warning: Required prop `name` was not specified in `Person`
相關連接:Prop Validation
要在使用React中使用特殊符號,請使用String.fromCharCode()
。
// bad <div>PiCO · Mascot</div> // nope <div>PiCO · Mascot</div> // good <div>{'PiCO ' + String.fromCharCode(183) + ' Mascot'}</div> // better <div>{`PiCO ${String.fromCharCode(183)} Mascot`}</div>
相關連接:HTML Entities
瀏覽器認爲你是愚蠢的,可是React不這麼人爲。請始終爲你的table組件添加tbody。
// bad render () { return ( <table> <tr>...</tr> </table> ); } // good render () { return ( <table> <tbody> <tr>...</tr> </tbody> </table> ); }
瀏覽器會自動插入tbody當你忘了寫它。React則不會,這樣會給你的代碼帶來混亂,請記住使用tbody。
使用classNames管理你的classes邏輯。
// bad get classes () { let classes = ['MyComponent']; if (this.state.active) { classes.push('MyComponent--active'); } return classes.join(' '); } render () { return <div className={this.classes} />; }
// good render () { let classes = { 'MyComponent': true, 'MyComponent--active': this.state.active }; return <div className={classnames(classes)} />; }