创建组件的三种方式
弃用 Mixins
命名
声明组件
代码缩进
使用双引号
空格
属性
Refs
括号
标签
函数/方法
组件生命周期书写顺序
弃用 isMounted
原则上每个文件只写一个组件, 多个无状态组件可以放在单个文件中. eslint: react/no-multi-comp.
推荐使用 JSX 语法编写 React 组件, 而不是 React.createElement
Class vs React.createClass vs stateless
如果你的组件有内部状态或者是refs, 推荐使用 class extends React.Component 而不是 React.createClass.
eslint: react/prefer-es6-class react/prefer-stateless-function
// bad
const Listing = React.createClass({
// ...
render() {
return {this.state.hello};
}
});
// good
class Listing extends React.Component {
// ...
render() {
return {this.state.hello};
}
}
// bad
class Listing extends React.Component {
render() {
return {this.props.hello};
}
}
// bad (relying on function name inference is discouraged)
const Listing = ({ hello }) => (
{hello}
);
// good
function Listing({ hello }) {
return {hello};
}
不要使用 mixins.
因为 Mixins 会增加隐式依赖, 导致命名冲突, 并且会增加复杂度.大多数情况下, 可以更好的方法代替 Mixins, 如:组件化, 高阶组件, 工具组件等.
扩展名: React 组件使用 .jsx 扩展名.
// bad
import reservationCard from "./ReservationCard";
// good
import ReservationCard from "./ReservationCard";
// bad
const ReservationItem = ;
// good
const reservationItem = ;
组件命名: 组件名与当前文件名一致. 如 ReservationCard.jsx 应该包含名为 ReservationCard的组件. 如果整个目录是一个组件, 使用 index.js作为入口文件, 然后直接使用 index.js 或者目录名作为组件的名称:
// bad
import Footer from "./Footer/Footer";
// bad
import Footer from "./Footer/index";
// good
import Footer from "./Footer"
高阶组件命名: 生成一个新的组件时, 其中的组件名 displayName 应该为高阶组件名和传入组件名的组合. 例如, 高阶组件 withFoo(), 当传入一个 Bar 组件的时候, 生成的组件名 displayName 应该为 withFoo(Bar).
因为一个组件的 displayName 可能在调试工具或错误信息中使用到. 清晰合理的命名, 能帮助我们更好的理解组件执行过程, 更好的 Debug.
// bad
export default function withFoo(WrappedComponent) {
return function WithFoo(props) {
return ;
}
}
// good
export default function withFoo(WrappedComponent) {
function WithFoo(props) {
return ;
}
const wrappedComponentName = WrappedComponent.displayName
|| WrappedComponent.name
|| "Component";
WithFoo.displayName = `withFoo(${wrappedComponentName})`;
return WithFoo;
}
属性命名: 避免使用 DOM 相关的属性来用命名自定义属性
因为对于style 和 className 这样的属性名, 我们都会默认它们代表一些特殊的含义.
// bad
export default React.createClass({
displayName: "ReservationCard",
// stuff goes here
});
// good
export default class ReservationCard extends React.Component {
}
代码缩进
遵循以下的 JSX 语法缩进/格式. eslint: react/jsx-closing-bracket-location
// bad
// good, 有多行属性的话, 新建一行关闭标签
// 若能在一行中显示, 直接写成一行
// 子元素按照常规方式缩进
使用双引号
对于 JSX 属性值总是使用双引号(“), 其他均使用单引号(”). eslint: jsx-quotes
因为 HTML 属性也是用双引号, 因此 JSX 的属性也遵循此约定.
// bad
// good
// bad
// good
空格
总是在自动关闭的标签前加一个空格, 正常情况下不需要换行. eslint: no-multi-spaces, react/jsx-tag-spacing
// bad
// very bad
// bad
// good
不要在JSX {} 引用括号里两边加空格. eslint: react/jsx-curly-spacing
// bad
// good
属性
JSX 属性名使用骆驼式风格camelCase.
// bad
// good
如果属性值为 true, 可以直接省略. eslint: react/jsx-boolean-value
// bad
// good
< img > 标签总是添加 alt 属性. 如果图片以陈述方式显示, alt 可为空, 或者< img > 要包含role=“presentation”. eslint: jsx-a11y/alt-text
// bad
// good
// good
// good
不要在 alt 值里使用如 “image”, “photo”, or “picture” 包括图片含义这样的词, 中文同理. eslint: jsx-a11y/img-redundant-alt
因为屏幕助读器已经把 img 标签标注为图片了, 所以没有必要再在 alt 里重复说明.
// bad
// good
使用有效正确的 aria role属性值 ARIA roles. eslint: jsx-a11y/aria-role
// bad - not an ARIA role
// bad - abstract ARIA role
// good
不要在标签上使用 accessKey 属性. eslint: jsx-a11y/no-access-key
因为屏幕助读器在键盘快捷键与键盘命令时造成的不统一性会导致阅读性更加复杂.
// bad
// good
避免使用数组的 index 来作为属性key的值, 推荐使用唯一ID. (Index as a key is an anti pattern)
// bad
{todos.map((todo, index) =>
)}
// good
{todos.map(todo => (
))}
对于所有非必填写属性, 总是手动去定义defaultProps属性.
因为 propTypes 可以作为组件的文档说明, 而声明 defaultProps 使阅读代码的人不需要去假设默认值. 另外, 显式的声明默认属性可以让你的组件跳过属性类型的检查.
// bad
function SFC({ foo, bar, children }) {
return {foo}{bar}{children};
}
SFC.propTypes = {
foo: PropTypes.number.isRequired,
bar: PropTypes.string,
children: PropTypes.node,
};
// good
function SFC({ foo, bar, children }) {
return {foo}{bar}{children};
}
SFC.propTypes = {
foo: PropTypes.number.isRequired,
bar: PropTypes.string,
children: PropTypes.node,
};
SFC.defaultProps = {
bar: "",
children: null,
};
Refs
总是使用回调函数方式定义 ref. eslint: react/no-string-refs
// bad
// good
{ this.myRef = ref; }}
/>
括号
将多行 JSX 标签写在 ()里. eslint: react/jsx-wrap-multilines
// bad
render() {
return
;
}
// good
render() {
return (
);
}
// good, 单行可以不需要
render() {
const body = hello;
return {body} ;
}
标签
对于没有子元素的标签, 总是自关闭标签. eslint: react/self-closing-comp
// bad
// good
如果组件有多行的属性, 关闭标签时新建一行. eslint: react/jsx-closing-bracket-location
// bad
// good
函数/方法
使用箭头函数来获取本地变量.
function ItemList(props) {
return (
{props.items.map((item, index) => (
- doSomethingWith(item.name, index)}
/>
))}
);
}
当在 render() 里使用事件处理方法时, 提前在构造函数里把 this 绑定上去. eslint: react/jsx-no-bind
因为在每次 render 过程中, 再调用 bind 都会新建一个新的函数, 浪费资源.
// bad
class extends React.Component {
onClickDiv() {
// do stuff
}
render() {
return ;
}
}
// good
class extends React.Component {
constructor(props) {
super(props);
this.onClickDiv = this.onClickDiv.bind(this);
}
onClickDiv() {
// do stuff
}
render() {
return ;
}
}
在React组件中, 不要给所谓的私有函数添加 _ 前缀, 本质上它并不是私有的.
因为_ 下划线前缀在某些语言中通常被用来表示私有变量或者函数. 但是不像其他的一些语言, 在 JS 中没有原生支持所谓的私有变量, 所有的变量函数都是共有的. 了解更多详情请查看 Issue #1024, 和 #490 .
// bad
React.createClass({
_onClickSubmit() {
// do stuff
},
// other stuff
});
// good
class extends React.Component {
onClickSubmit() {
// do stuff
}
// other stuff
}
在 render 方法中总是确保 return 返回值. eslint: react/require-render-return
// bad
render() {
();
}
// good
render() {
return ();
}
组件生命周期书写顺序
class extends React.Component 的生命周期函数:
static 方法(可选)
constructor 构造函数
getChildContext 获取子元素内容
componentWillMount 组件渲染前
componentDidMount 组件渲染后
componentWillReceiveProps 组件将接受新的数据
shouldComponentUpdate 判断组件是否需要重新渲染
componentWillUpdate 上面的方法返回 true时, 组件将重新渲染
componentDidUpdate 组件渲染结束
componentWillUnmount 组件将从DOM中清除, 做一些清理任务
事件绑定 如 onClickSubmit() 或 onChangeDescription()
render 里的 getter 方法 如 getSelectReason() 或 getFooterContent()
可选的 render 方法 如 renderNavigation() 或 renderProfilePicture()
render render() 方法
如何定义 propTypes, defaultProps, contextTypes 等属性…
import React, { PropTypes } from "react";
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 {this.props.text};
}
}
Link.propTypes = propTypes;
Link.defaultProps = defaultProps;
export default Link;