原文:
代码结构
-
class definition
-
constructor
event handlers
'component' lifecycle
getters
render
-
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 ({this.props.name} {this.smilingMessage}); },}Person.defaultProps = { name: 'Guest'};Person.propTypes = { name: React.PropTypes.string};
格式化属性
当有2个以上属性时,就换行显示
// bad// good
// bad// good
依赖属性
使用getters方法代替定义依赖属性
// bad firstAndLastName () { return `${this.props.firstName} ${this.props.lastname}`; } // good get fullName () { return `${this.props.firstName} ${this.props.lastname}`; }
依赖状态
使用getters方法代替定义依赖状态,注意为了提高可读性需要在命名时加上一个动词前缀。
// badhappyAndKnowsIt () { return this.state.happy && this.state.knowsIt;}
// goodget isHappyAndKnowsIt () { return this.state.happy && this.state.knowsIt;}
这些方法必须返回boolean
类型
用三元运算代替Sub-render方法
保证渲染逻辑都写在render
方法里
// badrenderSmilingStatement () { return {(this.state.isSmiling) ? " is smiling." : ""};},render () { return{this.props.name}{this.renderSmilingStatement()};}
// goodrender () { return ({this.props.name} {(this.state.smiling) ? is smiling : null });}
视图组件
用定义的组件组成视图。不要创建混杂着布局和功能的一次性组件
// badclass PeopleWrappedInBSRow extends React.Component { render () { return (); }}
// goodclass BSRow extends React.Component { render () { return{this.props.children}; }}class SomeView extends React.Component { render () { return (); }}
容器组件(有状态组件)
容器组件负责获取数据并交付给相应的子组件渲染,仅此而已。— Jason Bonta
// bad// CommentList.jsclass 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 (
- {this.state.comments.map(({body, author}) => { return
- {body}—{author} ; })}
//good// CommentList.jsclass CommentList extends React.Component { render() { return (
- {this.props.comments.map(({body, author}) => { return
- {body}—{author} ; })}
相关链接:
在render
中缓存状态
不要在render
中缓存状态
// badrender () { let name = `Mrs. ${this.props.name}`; return{name};}// goodrender () { return{`Mrs. ${this.props.name}`};}
// bestget fancyName () { return `Mrs. ${this.props.name}`;}render () { return{this.fancyName};}
这里多半是出于代码风格的考虑,不过还是保持比较好,我怀疑也可能跟性能有关。
复合条件
不要把复合条件判断放在render
里。
// badrender () { return{if (this.state.happy && this.state.knowsIt) { return "Clapping hands" };}
// betterget isTotesHappy() { return this.state.happy && this.state.knowsIt;},render() { return{(this.isTotesHappy) && "Clapping hands"};}
这里最好的解决方案是使用容器组件来管理你的状态然后在通过属性(props)往下层传递。
检查空值
不要去检查是否存在某个prop
值,快使用defaultProps
。
// badrender () { if (this.props.person) { return{this.props.person.firstName}; } else { return null; }}
// goodclass MyComponent extends React.Component { render() { return{this.props.person.firstName}; }}MyComponent.defaultProps = { person: { firstName: 'Guest' }};
当你的值是对象或者数组时,使用 PropTypes.shape声明嵌套数据的预期类型。
通过Props设置State
不要通过props值去设置state,除非明显是个初始值。
// badgetInitialState () { return { items: this.props.items };}
// goodgetInitialState () { return { items: this.props.initialItems };}
详细请阅读官网的
命名事件响应方法
// badpunchABadger () { /*...*/ },render () { return ;}
// goodhandleClick () { /*...*/ },render () { return ;}
处理方法的命名必须:
第一个单词为handle
最后一个单词为要响应的事件(比如Click,Change)
现在时态
如果为了避免命名冲突,你可以在handle和事件名中间加入其他信息。比如,你可以定义handleNameChange 和handleAgeChange来区分onChange的不同响应处理。不过当你这样做的时候,你要问问自己是否需要一个新的组件了。
命名事件
可以使用自定义事件替代预设的事件名。
class Owner extends React.Component { handleDelete () { // handle Ownee's onDelete event } render () { return; }}class Ownee extends React.Component { render () { return ; }}Ownee.propTypes = { onDelete: React.PropTypes.func.isRequired};
使用PropTypes
使用PropTypes可以预先定义属性的类型,可以在之后获得一些有意义的警告信息。
MyValidatedComponent.propTypes = { name: React.PropTypes.string};
MyValidatedComponent
的name
属性值如果不是string
类型的话, 会输出警告。
// Warning: Invalid prop `name` of type `number` supplied to `MyValidatedComponent`, expected `string`.
在这里也可以设置属性是否是必须存在的。
MyValidatedComponent.propTypes = { name: React.PropTypes.string.isRequired}
这个组件会验证是否存在name
属性。
// Warning: Required prop `name` was not specified in `Person`
相关链接:
使用特殊符号
要在使用React中使用特殊符号,请使用String.fromCharCode()
。
// badPiCO · Mascot// nopePiCO · Mascot// good{'PiCO ' + String.fromCharCode(183) + ' Mascot'}// better{`PiCO ${String.fromCharCode(183)} Mascot`}
相关链接:
Tables
浏览器认为你是愚蠢的,但是React不这么人为。请始终为你的table组件添加tbody。
// badrender () { return (
浏览器会自动插入tbody当你忘了写它。React则不会,这样会给你的代码带来混乱,请记住使用tbody。
classnames
使用管理你的classes逻辑。
// badget classes () { let classes = ['MyComponent']; if (this.state.active) { classes.push('MyComponent--active'); } return classes.join(' ');}render () { return ;}
// goodrender () { let classes = { 'MyComponent': true, 'MyComponent--active': this.state.active }; return ;}
相关链接: