参考

airbnb:https://github.com/airbnb/javascript/tree/master/react

airbnb官方

基本规范

  • 每个文件只写一个模块.
    • 但多个无状态模块可以放在单个文件中. eslint: [react/no-multi-comp](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/no-multi-comp.md#ignorestateless).
  • 推荐使用 TSX 语法.
  • 不要使用 React.createElement,除非在从一个非 JSX 的文件中初始化 app.

    Alignment 代码对齐

  • 遵循以下的JSX语法缩进/格式. eslint: [react/jsx-closing-bracket-location](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-bracket-location.md) [react/jsx-closing-tag-location](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-closing-tag-location.md)
    ```jsx // bad

// good

// if props fit in one line then keep it on the same line // children get indented normally

// bad {showButton && }

// bad { showButton && }

// good {showButton && ( )}

// good {showButton && }

// good {someReallyLongConditional && anotherLongConditional && ( ) }

// good {someConditional ? ( ) : ( )}

  1. <a name="dgI4t"></a>
  2. #### Quotes 单引号还是双引号
  3. - 对于JSX属性值总是使用双引号(`"`), 其他均使用单引号(`'`). eslint: `[jsx-quotes](http://eslint.org/docs/rules/jsx-quotes)`
  4. > 为什么? HTML属性也是用双引号, 因此JSX的属性也遵循此约定.
  5. ```jsx
  6. // bad
  7. <Foo bar='bar' />
  8. // good
  9. <Foo bar="bar" />
  10. // bad
  11. <Foo style={{ left: "20px" }} />
  12. // good
  13. <Foo style={{ left: '20px' }} />

Spacing 空格

  • 总是在自动关闭的标签前加一个空格,正常情况下也不需要换行. eslint: [no-multi-spaces](http://eslint.org/docs/rules/no-multi-spaces), [react/jsx-tag-spacing](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-tag-spacing.md)
    ```jsx // bad

// very bad

// bad

// good

  1. - 不要在JSX `{}` 引用括号里两边加空格. eslint: `[react/jsx-curly-spacing](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-curly-spacing.md)`
  2. ```jsx
  3. // bad
  4. <Foo bar={ baz } />
  5. // good
  6. <Foo bar={baz} />

Props 属性

  • JSX 属性名使用小骆驼拼写法camelCase,如果属性名是一个 React 组件名,则使用大骆驼拼写法 PascalCase
    ```jsx // bad

// good

  1. - 如果属性值为 `true`, 可以直接省略. eslint: `[react/jsx-boolean-value](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-boolean-value.md)`
  2. ```jsx
  3. // bad
  4. <Foo
  5. hidden={true}
  6. />
  7. // good
  8. <Foo
  9. hidden
  10. />
  11. // good
  12. <Foo hidden />
  • <img> 标签总是添加 alt 属性. 如果图片以presentation(感觉是以类似PPT方式显示?)方式显示,alt 可为空, 或者<img> 要包含role="presentation". eslint: [jsx-a11y/alt-text](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/alt-text.md)
    ```jsx // bad React规范 - 图1

// good Me waving hello

// good React规范 - 图3

// good React规范 - 图4

  1. - 不要在 `alt` 值里使用如 "image", "photo", or "picture"包括图片含义这样的词, 中文也一样. eslint: `[jsx-a11y/img-redundant-alt](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/img-redundant-alt.md)`
  2. > 为什么? 屏幕助读器已经把 `img` 标签标注为图片了, 所以没有必要再在 `alt` 里说明了.
  3. ```jsx
  4. // bad
  5. <img src="hello.jpg" alt="Picture of me waving hello" />
  6. // good
  7. <img src="hello.jpg" alt="Me waving hello" />
  • 使用有效正确的 aria role属性值 ARIA roles. eslint: [jsx-a11y/aria-role](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/aria-role.md)
    ```jsx // bad - not an ARIA role

// bad - abstract ARIA role

// good

  1. - 不要在标签上使用 `accessKey` 属性. eslint: `[jsx-a11y/no-access-key](https://github.com/evcohen/eslint-plugin-jsx-a11y/blob/master/docs/rules/no-access-key.md)`
  2. > 为什么? 屏幕助读器在键盘快捷键与键盘命令时造成的不统一性会导致阅读性更加复杂.
  3. ```jsx
  4. // bad
  5. <div accessKey="h" />
  6. // good
  7. <div />
  • 避免使用数组的 index 来作为 key 属性的值。
    应当使用稳定不变的 ID。(使用不稳定的 ID 是一个反面模式,会降低性能、造成组件状态出错) 。特别是当元素的顺序可能改变的情况下,不应使用数组的 index 作为 key.

    key 属性指名称为 key 的属性,即 props.key

  1. // bad
  2. {todos.map((todo, index) =>
  3. <Todo
  4. {...todo}
  5. key={index}
  6. />
  7. )}
  8. // good
  9. {todos.map(todo => (
  10. <Todo
  11. {...todo}
  12. key={todo.id}
  13. />
  14. ))}
  • 尽可能少地使用扩展运算符

为什么? 除非你很想传递一些不必要的属性。对于React v15.6.1和更早的版本,你可以给DOM传递一些无效的HTML属性

例外情况:

  • 使用了变量提升的高阶组件
  1. function HOC(WrappedComponent) {
  2. return class Proxy extends React.Component {
  3. Proxy.propTypes = {
  4. text: PropTypes.string,
  5. isLoading: PropTypes.bool
  6. };
  7. render() {
  8. return <WrappedComponent {...this.props} />
  9. }
  10. }
  11. }
  • 只有在清楚明白扩展对象时才使用扩展运算符。这非常有用尤其是在使用Mocha测试组件的时候。
  1. export default function Foo {
  2. const props = {
  3. text: '',
  4. isPublished: false
  5. }
  6. return (<div {...props} />);
  7. }

特别提醒:尽可能地筛选出不必要的属性。同时,使用prop-types-exact来预防问题出现。

  1. // bad
  2. render() {
  3. const { irrelevantProp, ...relevantProps } = this.props;
  4. return <WrappedComponent {...this.props} />
  5. }
  6. // good
  7. render() {
  8. const { irrelevantProp, ...relevantProps } = this.props;
  9. return <WrappedComponent {...relevantProps} />
  10. }

Parentheses 括号

  • 将多行的JSX标签写在 ()里. eslint: [react/jsx-wrap-multilines](https://github.com/yannickcr/eslint-plugin-react/blob/master/docs/rules/jsx-wrap-multilines.md)
    ```jsx // bad render() { return
    1. <MyChild />
    2. </MyComponent>;
    }

// good render() { return ( ); }

// good, 单行可以不需要 render() { const body =

hello
; return {body}; }

  1. <a name="UuLKB"></a>
  2. ####
  3. <a name="I3CvC"></a>
  4. # 补充
  5. <a name="bN6M0"></a>
  6. #### 使用函数式组件,不使用class组件
  7. <a name="eRFfQ"></a>
  8. #### 组件卸载掉时候不要忘记清除定时器
  9. <a name="kcDZy"></a>
  10. #### 组件不推荐超过500行,否则难以阅读
  11. <a name="uVHPU"></a>
  12. #### 组件名和导出名应一致
  13. <a name="Z9Ne7"></a>
  14. #### 使用useMemo缓存复杂计算
  15. <a name="LQzsz"></a>
  16. #### <br />
  17. <a name="uMSvS"></a>
  18. #### 使用useCallBack缓存函数
  19. <a name="bhio2"></a>
  20. #### 使用useRef
  21. ```jsx
  22. // bad
  23. <Foo
  24. ref="myRef"
  25. />
  26. // bad
  27. <Foo
  28. ref={(ref) => { this.myRef = ref; }}
  29. />
  30. //Good
  31. const ref = useRef(null);
  32. <Foo
  33. ref={ref}
  34. />

useMount代替useEffect

  1. //bad
  2. useEffect(()=> {
  3. //
  4. },[])
  5. //good
  6. useMount(()=> {
  7. //
  8. })

render 不要太臃肿, 一眼可以看完,可以通过拆分组件简化

尽量多用selector ,不要自己在组件中计算很多

  1. const selectValue = createSelector(
  2. state => state.values.value1,
  3. state => state.values.value2,
  4. (value1, value2) => value1 + value2
  5. )

“有状态无渲染,有渲染无状态” 尽量做到

尽量做到逻辑和UI视图分离

页面入口文件结构简单,长逻辑抽 hooks分离, 长 render拆分组件

image.png

组件文件名大写,和Compoent保持一致

多使用自定义hooks减少代码,例如ahooks

组件名称和定义该组件的文件名称建议要保持一致

循环列表不要忘了key,不推荐使用index作为key值

不要滥用redux,能用state解决的就不用redux

合理使用 useMemo 取代 useState + useEffect

  1. // bad
  2. function Son ({data}) {
  3. const [fliterData, setFliterrData] = useState(data)
  4. useEffect(() => {
  5. setFliterrData(data => {...})
  6. }, [data])
  7. }
  8. // good
  9. const filterData = useMemo(() => {
  10. return data.filter((item) => doSthing())
  11. );
  12. }, [data]);

useEffect 依赖过多

  1. // bad
  2. function Component({id, name}) {
  3. useEffect(() => {
  4. /* do something */
  5. setId(id)
  6. setName(name)
  7. }, [id, name,...更多]) // 当依赖越多的时候,复杂度就越来越高
  8. }
  9. // good
  10. function Component({id, name}) {
  11. useEffect(() => {
  12. /* do something */
  13. setId(id)
  14. }, [id])
  15. useEffect(() => {
  16. /* do something */
  17. setName(name)
  18. }, [name])
  19. }

禁止在render中写大段函数,抽出去

  1. //bad
  2. <Button onclick={()=> {
  3. ...
  4. ...
  5. ...
  6. }}>button </Button>
  7. //good
  8. <Button onclick={()=> onClickBtn()}>button </Button>

除非确定值不会为零,否则使用三元控制是否渲染

因为react会渲染0值

  1. //bad
  2. { val && <Component /> }
  3. //good
  4. { val ? <Component /> : null}