React 风格指南
React 样式指南 (2021)
React 样式指南 (2021)
src:原帖:https://github.com/airbnb/javascript/tree/master/react
我写这篇文章的目的是为了提醒大家,对于刚开始学习 React 的人来说,什么是重要的。因此,我希望收到大家的评论。
基本规则
- 每个文件仅包含一个 React 组件。
- 始终使用 JSX 语法。
命名
- 列表 itemExtensions:使用
.jsx
React 组件的扩展。eslint:react/jsx-filename-extension - Filename:用于
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)
。为什么?组件
displayName
可能被开发者工具或错误消息使用,并且具有清晰表达这种关系的值有助于人们理解正在发生的事情。// 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; }
宣言
-
不要用它
displayName
来命名组件。请通过引用来命名组件。// bad export default React.createClass({ displayName: 'ReservationCard', // stuff goes here }); // good export default function ReservationCard(props) { return () }
结盟
-
遵循 JSX 语法的这些对齐样式。eslint:
react/jsx-closing-bracket-location
react/jsx-closing-tag-location
// 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 />} // good {someReallyLongConditional && anotherLongConditional && ( <Foo superLongParam="bar" anotherSuperLongParam="baz" /> ) } // good {someConditional ? ( <Foo /> ) : ( <Foo superLongParam="bar" anotherSuperLongParam="baz" /> )}
道具
-
始终使用camelCase作为 prop 名称,如果 prop 值是 React 组件,则使用 PascalCase 。
// bad <Foo UserName="hello" phone_number={12345678} /> // good <Foo userName="hello" phoneNumber={12345678} Component={SomeComponent} />
-
当明确指定 prop 的值时,省略该值
true
。eslint:react/jsx-boolean-value
// bad <Foo hidden={true} /> // good <Foo hidden /> // very good <Foo hidden />
-
避免使用数组索引作为
key
prop,最好使用稳定的 ID。eslint:react/no-array-index-key
为什么?不使用稳定的 ID是一种反模式,因为它会对性能产生负面影响,并导致组件状态出现问题。
如果项目的顺序可能会改变,我们不建议对键使用索引。
// bad
{todos.map((todo, index) =>
<Todo
{...todo}
key={index}
/>
)}
// good
{todos.map(todo => (
<Todo
{...todo}
key={todo.id}
/>
))}
- 始终为所有非必需的 props 定义明确的 defaultProps。
为什么?propTypes 是一种文档形式,提供 defaultProps 意味着代码的读者不必做太多假设。此外,这还意味着你的代码可以省略某些类型检查。
// 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,
};
- 谨慎使用扩展 props。> 为什么?否则,你更有可能将不必要的 props 传递给组件。对于 React v15.6.1 及更早版本,你可能会将无效的 HTML 属性传递给 DOM。
例外:
- 代理 props 并提升 propTypes 的 HOC
function HOC(WrappedComponent) {
return class Proxy extends React.Component {
Proxy.propTypes = {
text: PropTypes.string,
isLoading: PropTypes.bool
};
render() {
return <WrappedComponent {...this.props} />
}
}
}
- 使用已知的、显式的 props 来展开对象。这在使用 Mocha 的 beforeEach 结构测试 React 组件时尤其有用。
export default function Foo {
const props = {
text: '',
isPublished: false
}
return (<div {...props} />);
}
使用说明:
尽可能过滤掉不必要的 props。此外,使用prop-types-exact有助于防止 bug。
// bad
render() {
const { irrelevantProp, ...relevantProps } = this.props;
return <WrappedComponent {...this.props} />
}
// good
render() {
const { irrelevantProp, ...relevantProps } = this.props;
return <WrappedComponent {...relevantProps} />
}
参考文献
-
始终使用 ref 回调。eslint:
react/no-string-refs
// bad <Foo ref="myRef" /> // good <Foo ref={(ref) => { this.myRef = ref; }} />
括号
-
当 JSX 标签跨越多行时,请将其括在括号中。eslint:
react/jsx-wrap-multilines
// 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>; }
方法
-
使用箭头函数来覆盖局部变量。当你需要向事件处理程序传递额外数据时,它非常方便。但是,请确保它们不会严重损害性能,尤其是在传递给可能是 PureComponents 的自定义组件时,因为它们每次都会触发可能不必要的重新渲染。
function ItemList(props) { return ( <ul> {props.items.map((item, index) => ( <Item key={item.key} onClick={(event) => { doSomethingWith(event, item.name, index); }} /> ))} </ul> ); }
-
在构造函数中为 render 方法绑定事件处理程序。eslint:
react/jsx-no-bind
为什么?渲染路径中的绑定调用会在每次渲染时创建一个全新的函数。不要在类字段中使用箭头函数,因为这会增加测试和调试的难度,并可能对性能产生负面影响,而且从概念上讲,类字段用于存储数据,而不是逻辑。
// bad class extends React.Component { onClickDiv() { // do stuff } render() { return <div onClick={this.onClickDiv.bind(this)} />; } } // very bad class extends React.Component { onClickDiv = () => { // do stuff } render() { return <div onClick={this.onClickDiv} /> } } // 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 组件的内部方法使用下划线前缀。
为什么?在其他语言中,下划线前缀有时被用作表示隐私的惯例。但是,与这些语言不同,JavaScript 本身并不支持隐私,所有内容都是公开的。无论你的意图如何,在属性中添加下划线前缀并不会真正使其变为私有属性,任何属性(无论是否带有下划线前缀)都应被视为公开属性。有关更深入的讨论,请参阅问题#1024和#490 。
// bad React.createClass({ _onClickSubmit() { // do stuff }, // other stuff }); // good class extends React.Component { onClickSubmit() { // do stuff } // other stuff }
-
确保在你的
render
方法中返回一个值。eslint:react/require-render-return
// bad render() { (<div />); } // good render() { return (<div />); }