原文: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)} />; }