基本规则
- 每个文件只包含一个React组件。
- 但是,每个文件允许多个无状态或纯组件。
- 始终使用JSX语法。
React.createElement
除非您从不是JSX的文件初始化应用程序,否则请勿使用。
Class vs React.createClass
vs stateless
-
If you have internal state and/or refs, prefer
class extends React.Component
overReact.createClass
.// bad const Listing = React.createClass({ // ... render() { return <div>{this.state.hello}</div>; } }); // good class Listing extends React.Component { // ... render() { return <div>{this.state.hello}</div>; } }
And if you don’t have state or refs, prefer normal functions (not arrow functions) over classes:
// bad class Listing extends React.Component { render() { return <div>{this.props.hello}</div>; } } // bad (relying on function name inference is discouraged) const Listing = ({ hello }) => ( <div>{hello}</div> ); // good function Listing({ hello }) { return <div>{hello}</div>; }
命名
-
扩展:使用
.jsx
React组件的扩展。 -
文件名:使用PascalCase作为文件名。例如,
ReservationCard.jsx
。 -
参考命名:对其实例使用PascalCase用于React组件和camelCase。
-
// bad import reservationCard from './ReservationCard'; // good import ReservationCard from './ReservationCard'; // bad const ReservationItem = <ReservationCard />; // good const reservationItem = <ReservationCard />;
-
组件命名:使用文件名作为组件名称。例如,
ReservationCard.jsx
应该有一个引用名称ReservationCard
。但是,对于目录的根组件,请使用index.jsx
文件名并使用目录名作为组件名称:// bad import Footer from './Footer/Footer'; // bad import Footer from './Footer/index'; // good import Footer from './Footer';
-
高阶组件命名:使用高阶组件名称和传入组件名称的组合作为
displayName
生成组件的组合。例如,高次成分withFoo()
,通过当组件Bar
应该产生一个组分与displayName
的withFoo(Bar)
。// bad export default function withFoo(WrappedComponent) { return function WithFoo(props) { return <WrappedComponent {...props} foo />; } } // good export default function withFoo(WrappedComponent) { function WithFoo(props) { return <WrappedComponent {...props} foo />; } const wrappedComponentName = WrappedComponent.displayName || WrappedComponent.name || 'Component'; WithFoo.displayName = `withFoo(${wrappedComponentName})`; return WithFoo; }
-
道具命名:避免将DOM组件道具名称用于不同目的。
// bad <MyComponent style="fancy" /> // bad <MyComponent className="fancy" /> // good <MyComponent variant="fancy" />
宣言
-
不要
displayName
用于命名组件。而是通过引用命名组件。
-
// bad export default React.createClass({ displayName: 'ReservationCard', // stuff goes here }); // good export default class ReservationCard extends React.Component { }
对准
-
遵循JSX语法的这些对齐样式。
-
// bad <Foo superLongParam="bar" anotherSuperLongParam="baz" /> // good <Foo superLongParam="bar" anotherSuperLongParam="baz" /> // if props fit in one line then keep it on the same line <Foo bar="bar" /> // children get indented normally <Foo superLongParam="bar" anotherSuperLongParam="baz" > <Quux /> </Foo> // bad {showButton && <Button /> } // bad { showButton && <Button /> } // good {showButton && ( <Button /> )} // good {showButton && <Button />}
行情
-
始终
"
对JSX属性使用双引号(),但'
对所有其他JS使用单引号()。 -
// bad <Foo bar='bar' /> // good <Foo bar="bar" /> // bad <Foo style={{ left: "20px" }} /> // good <Foo style={{ left: '20px' }} />
间距
-
始终在自动关闭标签中包含一个空格。
// bad <Foo/> // very bad <Foo /> // bad <Foo /> // good <Foo />
-
不要用空格填充JSX花括号。
// bad <Foo bar={ baz } /> // good <Foo bar={baz} />
道具
-
始终使用camelCase作为道具名称。
// bad <Foo UserName="hello" phone_number={12345678} /> // good <Foo userName="hello" phoneNumber={12345678} />
-
明确时,忽略道具的值
true。
// bad <Foo hidden={true} /> // good <Foo hidden /> // good <Foo hidden />
-
始终
alt
在<img>
标签上包含道具。如果图像是表现形式,alt
则可以是空字符串或<img>
必须具有的字符串role="presentation"
。// bad <img src="hello.jpg" /> // good <img src="hello.jpg" alt="Me waving hello" /> // good <img src="hello.jpg" alt="" /> // good <img src="hello.jpg" role="presentation" />
-
不要在
<img>
alt
道具中使用“图像”,“照片”或“图片”等字样。// bad <img src="hello.jpg" alt="Picture of me waving hello" /> // good <img src="hello.jpg" alt="Me waving hello" />
-
Use only valid, non-abstract ARIA roles. eslint:
jsx-a11y/aria-role
// bad - not an ARIA role <div role="datepicker" /> // bad - abstract ARIA role <div role="range" /> // good <div role="button" />
-
仅使用有效的非抽象ARIA角色。
// bad <div accessKey="h" /> // good <div />
- 不要
accessKey
在元素上使用。
避免使用数组索引作为key
prop,更喜欢稳定的ID
// bad {todos.map((todo, index) => <Todo {...todo} key={index} /> )} // good {todos.map(todo => ( <Todo {...todo} key={todo.id} /> ))}
- 始终为所有不需要的道具定义显式defaultProp。
// bad function SFC({ foo, bar, children }) { return <div>{foo}{bar}{children}</div>; } SFC.propTypes = { foo: PropTypes.number.isRequired, bar: PropTypes.string, children: PropTypes.node, }; // good function SFC({ foo, bar, children }) { return <div>{foo}{bar}{children}</div>; } SFC.propTypes = { foo: PropTypes.number.isRequired, bar: PropTypes.string, children: PropTypes.node, }; SFC.defaultProps = { bar: '', children: null, };
- 谨慎使用传播道具。
例外:
- 代理道具并提升propTypes的HOC
function HOC(WrappedComponent) { return class Proxy extends React.Component { Proxy.propTypes = { text: PropTypes.string, isLoading: PropTypes.bool }; render() { return <WrappedComponent {...this.props} /> } } }
- 使用已知的显式道具传播对象。当使用Mocha的beforeEach构造测试React组件时,这可能特别有用。
export default function Foo { const props = { text: '', isPublished: false } return (<div {...props} />); }
使用注意事项:尽可能过滤掉不必要的道具。另外,使用prop-types-exact来帮助防止错误。
// bad render() { const { irrelevantProp, ...relevantProps } = this.props; return <WrappedComponent {...this.props} /> } // good render() { const { irrelevantProp, ...relevantProps } = this.props; return <WrappedComponent {...relevantProps} /> }
参考文献
-
始终使用ref回调。
// bad <Foo ref="myRef" /> // good <Foo ref={(ref) => { this.myRef = ref; }} />
括弧
-
当它们跨越多行时,在括号中包装JSX标记。
-
// bad render() { return <MyComponent variant="long body" foo="bar"> <MyChild /> </MyComponent>; } // good render() { return ( <MyComponent variant="long body" foo="bar"> <MyChild /> </MyComponent> ); } // good, when single line render() { const body = <div>hello</div>; return <MyComponent>{body}</MyComponent>; }
标签
-
总是自我关闭没有孩子的标签
-
// bad <Foo variant="stuff"></Foo> // good <Foo variant="stuff" />
-
如果组件具有多行属性,请在新行上关闭其标记。
// bad <Foo bar="bar" baz="baz" /> // good <Foo bar="bar" baz="baz" />
方法
-
使用箭头函数关闭局部变量。
-
function ItemList(props) { return ( <ul> {props.items.map((item, index) => ( <Item key={item.key} onClick={() => doSomethingWith(item.name, index)} /> ))} </ul> ); }
-
绑定构造函数中render方法的事件处理程序。
// bad class extends React.Component { onClickDiv() { // do stuff } render() { return <div onClick={this.onClickDiv.bind(this)} />; } } // good class extends React.Component { constructor(props) { super(props); this.onClickDiv = this.onClickDiv.bind(this); } onClickDiv() { // do stuff } render() { return <div onClick={this.onClickDiv} />; } }
-
不要对React组件的内部方法使用下划线前缀。
// bad React.createClass({ _onClickSubmit() { // do stuff }, // other stuff }); // good class extends React.Component { onClickSubmit() { // do stuff } // other stuff }
-
请务必在
render
方法中返回一个值。// bad render() { (<div />); } // good render() { return (<div />); }
-
如何定义
propTypes
,defaultProps
,contextTypes
, etc...import React from 'react'; import PropTypes from 'prop-types'; const propTypes = { id: PropTypes.number.isRequired, url: PropTypes.string.isRequired, text: PropTypes.string, }; const defaultProps = { text: 'Hello World', }; class Link extends React.Component { static methodsAreOk() { return true; } render() { return <a href={this.props.url} data-id={this.props.id}>{this.props.text}</a>; } } Link.propTypes = propTypes; Link.defaultProps = defaultProps; export default Link;
以上是本人在使用react开发时遵循的一些语法规范。如有不足之处,欢迎大家给出建议!