react 项目结构及编码规范

文章详细介绍了React项目的推荐结构,包括src目录下各文件夹的用途,以及编码规范,如组件命名应使用大写字母开头,一个文件只包含一个React组件,避免使用mixins,使用JSX语法,props命名采用驼峰式等。此外,还强调了代码对齐、引号使用、空格处理、props的处理方式以及refs的正确使用等最佳实践。
摘要由CSDN通过智能技术生成

react 项目结构及编码规范

项目结构

project-name ---------------------------------- 项目名字
  build --------------------------------------- 打包后文件夹
  config -------------------------------------- webpack配置文件
  node-modules -------------------------------- 项目依赖第三方库
  scripts ------------------------------------- 打包,运行,测试脚本
  src ----------------------------------------- 项目源码文件夹
    assets ------------------------------------ 公共样式,字体等文件夹
    common ------------------------------------ 定义的工具函数、通用常量、ajax请求等公用组件
    components -------------------------------- 公用组件文件夹(提升为通用组件,以数据驱动为主)
    css --------------------------------------- 组件自定义样式文件夹
    pages ------------------------------------- 完成界面文件夹(组成项目中整个界面)
      module1 --------------------------------- 模块一
      module2 --------------------------------- 模块二
    **.js ------------------------------------- 项目入口文件
  test ---------------------------------------- 测试文件夹
  .babelrc ------------------------------------ 是babel配置文件
  package.json -------------------------------- 项目依赖库文件

编码规范

Table of Contents

  1. Basic Rules
  2. Class vs React.createClass vs stateless
  3. Mixins
  4. Naming
  5. Declaration
  6. Alignment
  7. Quotes
  8. Spacing
  9. Props
  10. Refs
  11. Parentheses
  12. Tags
  13. Methods
  14. Ordering
  15. isMounted

Basic Rules

  • Only include one React component per file. 一个文件包含一个 React Component 组件。
  • Always use JSX syntax. 使用 JSX 语法
  • Do not use React.createElement unless you’re initializing the app from a file that is not JSX.(不要使用 React.createElement 方法,除非你在初始化APP时的 index.js 中不使用 JSX 语法)

Class vs React.createClass vs stateless

  • If you have internal state and/or refs, prefer class extends React.Component over React.createClass. eslint: react/prefer-es6-class react/prefer-stateless-function

    将 React 类放在一个变量中(const Name = React.createClass),还是直接继承自组件(class Name extends React.Component)?如果内部含有state 或者refs 等,最好设置 React.Component. 如果仅仅是单向组件,只有props, 没有复杂用户交互,可以设置 createClass 或者 Purecomponent.

    // 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。如果没有 state 和 refs,只有 props 不需要使用箭头函数,直接使用普通函数传值即可。

    // 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>;
    }

Mixins

Why? Mixins introduce implicit dependencies, cause name clashes, and cause snowballing complexity. Most use cases for mixins can be accomplished in better ways via components, higher-order components, or utility modules.

不要使用混合组件:mixins 引入了深层依赖关系,可能名称冲突,并导致滚雪球式复杂性。mixin的大多数用例都可以通过组件、高阶组件、实用程序模块以更好的方式完成。

划重点:权责分明,避免深层引用。一个函数对应一个主要功能,一个组件对应界面的一个 UI 部分。尽量实现组件的继承和复用。

Naming

  • Extensions: Use .js extension for React components.

  • Filename: Use reservation-card for filenames. E.g., reservation-card.js.

    文件名使用小写开头(连接符)

    // bad
    import reservationCard from './reservation-card';
    
    // good
    import ReservationCard from './reservation-card';
    
    // bad
    const ReservationItem = <ReservationCard />;
    
    // good
    const reservationItem = <ReservationCard />;
  • Component Naming: Use the filename as the component name. For example, ReservationCard.jsx should have a reference name of ReservationCard. However, for root components of a directory, use index.jsx as the filename and use the directory name as the component name:

    React 组件使用大写开头,组件名和文件名相同(便于调用)。变量名使用小写开头(驼峰)

    // bad
    import Footer from './Footer/Footer';
    
    // bad
    import Footer from './Footer/index';
    
    // good
    import Footer from './Footer';
  • Higher-order Component Naming: Use a composite of the higher-order component’s name and the passed-in component’s name as the displayName on the generated component. For example, the higher-order component withFoo(), when passed a component Bar should produce a component with a displayName of withFoo(Bar).

    Why? A component’s displayName may be used by developer tools or in error messages, and having a value that clearly expresses this relationship helps people understand what is happening.

    // 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;
    }
  • Props Naming: Avoid using DOM component prop names for different purposes.

    Why? People expect props like style and className to mean one specific thing. Varying this API for a subset of your app makes the code less readable and less maintainable, and may cause bugs.

props不能和已有 HTML 属性重复

// bad
<MyComponent style="fancy" />

// bad
<MyComponent className="fancy" />

// good
<MyComponent variant="fancy" />

Declaration

  • Do not use displayName for naming components. Instead, name the component by reference.

    // bad
    export default React.createClass({
      displayName: 'ReservationCard',
      // stuff goes here
    });
    
    // good
    export default class ReservationCard extends React.Component {
    }

Alignment

  • Follow these alignment styles for JSX syntax. eslint: react/jsx-closing-bracket-location react/jsx-closing-tag-location 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 多行显示JSX
    {showButton && (
      <Button />
    )}
    
    // good
    {showButton && <Button />}

Quotes

  • Always use double quotes (") for JSX attributes, but single quotes (') for all other JS. eslint: jsx-quotes

    Why? Regular HTML attributes also typically use double quotes instead of single, so JSX attributes mirror this convention.

    // bad
    <Foo bar='bar' />
    
    // good
    <Foo bar="bar" />
    
    // bad
    <Foo style={{ left: "20px" }} />
    
    // good
    <Foo style={{ left: '20px' }} />

Spacing

  • Always include a single space in your self-closing tag. eslint: no-multi-spaces, react/jsx-tag-spacing

    // bad
    <Foo/>
    
    // very bad
    <Foo                 />
    
    // bad
    <Foo
     />
    
    // good
    <Foo />
  • Do not pad JSX curly braces with spaces. eslint: react/jsx-curly-spacing

    // bad
    <Foo bar={ baz } />
    
    // good
    <Foo bar={baz} />

Props

  • Always use camelCase for prop names.

    // bad
    <Foo
      UserName="hello"
      phone_number={12345678}
    />
    
    // good
    <Foo
      userName="hello"
      phoneNumber={12345678}
    />
  • Omit the value of the prop when it is explicitly true. eslint: react/jsx-boolean-value

    如果传值是 true 可以省略

    // bad
    <Foo
      hidden={true}
    />
    
    // good
    <Foo
      hidden
    />
    
    // good
    <Foo hidden />
  • Always include an alt prop on <img> tags. If the image is presentational, alt can be an empty string or the <img> must have role="presentation". eslint: jsx-a11y/alt-text

    // 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" />
  • Do not use words like "image", "photo", or "picture" in <img> alt props. eslint: jsx-a11y/img-redundant-alt

    Why? Screenreaders already announce img elements as images, so there is no need to include this information in the alt text.

    // 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" />
  • Do not use accessKey on elements. eslint: jsx-a11y/no-access-key

Why? Inconsistencies between keyboard shortcuts and keyboard commands used by people using screenreaders and keyboards complicate accessibility.

// bad
<div accessKey="h" />

// good
<div />
  • Avoid using an array index as key prop, prefer a stable ID.

Why? Not using a stable ID is an anti-pattern because it can negatively impact performance and cause issues with component state.

We don’t recommend using indexes for keys if the order of items may change.

注意:避免使用箭头函数的 index 作为子组件的 key 值。不使用稳定ID是一种反模式,因为它会对性能产生负面影响,并导致组件状态问题。如果子组件item可能变化是,例如评论,最好使用id不使用index。

// bad
{todos.map((todo, index) =>
  <Todo
    {...todo}
    key={index}
  />
)}

// good
{todos.map(todo => (
  <Todo
    {...todo}
    key={todo.id}
  />
))}
  • Always define explicit defaultProps for all non-required props.

Why? propTypes are a form of documentation, and providing defaultProps means the reader of your code doesn’t have to assume as much. In addition, it can mean that your code can omit certain type checks.

使用 SFC.defaultProps 可以让使用组件的人知道需要传入的参数和类型;同时写 propTypes 也更好

// 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,
};
  • Use spread props sparingly. 尽量少用 props 不要传没必要的 props

    Why? Otherwise you’re more likely to pass unnecessary props down to components. And for React v15.6.1 and older, you could pass invalid HTML attributes to the DOM.

Exceptions:

  • HOCs that proxy down props and hoist propTypes
function HOC(WrappedComponent) {
  return class Proxy extends React.Component {
    Proxy.propTypes = {
      text: PropTypes.string,
      isLoading: PropTypes.bool
    };

    render() {
      return <WrappedComponent {...this.props} />
    }
  }
}
  • Spreading objects with known, explicit props. This can be particularly useful when testing React components with Mocha’s beforeEach construct.
export default function Foo {
  const props = {
    text: '',
    isPublished: false
  }

  return (<div {...props} />);
}

Notes for use: Filter out unnecessary props when possible. Also, use prop-types-exact to help prevent bugs.

// bad
render() {
  const { irrelevantProp, ...relevantProps  } = this.props;
  return <WrappedComponent {...this.props} />
}

// good
render() {
  const { irrelevantProp, ...relevantProps  } = this.props;
  return <WrappedComponent {...relevantProps} />
}

Refs

  • Always use ref callbacks. eslint: react/no-string-refs

    使用箭头函数将refs绑定到属性上,避免直接使用字符串。

    // bad
    <Foo
      ref="myRef"
    />
    
    // good
    <Foo
      ref={(ref) => { this.myRef = ref; }}
    />

Parentheses

  • Wrap JSX tags in parentheses when they span more than one line. eslint: react/jsx-wrap-multilines

    return 多行加括号,单行不需要加括号

    // 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>;
    }

Tags

  • Always self-close tags that have no children. eslint: react/self-closing-comp

    // bad
    <Foo variant="stuff"></Foo>
    
    // good
    <Foo variant="stuff" />
  • If your component has multi-line properties, close its tag on a new line. eslint: react/jsx-closing-bracket-location

    // bad
    <Foo
      bar="bar"
      baz="baz" />
    
    // good
    <Foo
      bar="bar"
      baz="baz"
    />

Methods

  • Use arrow functions to close over local variables.

    function ItemList(props) {
      return (
        <ul>
          {props.items.map((item, index) => (
            <Item
              key={item.key}
              onClick={() => doSomethingWith(item.name, index)}
            />
          ))}
        </ul>
      );
    }
  • Bind event handlers for the render method in the constructor. eslint: react/jsx-no-bind

    Why? A bind call in the render path creates a brand new function on every single render.

    // bad
    class extends React.Component {
      onClickDiv() {
        // do stuff
      }
    
      render() {
        return <div onClick={this.onClickDiv.bind(this)} />;
      }
    }
    
    // good
    class extends React.Component {
    
      onClickDiv = () => {
        // do stuff
      }
    
      render() {
        return <div onClick={this.onClickDiv} />;
      }
    }
  • Do not use underscore prefix for internal methods of a React component. 组件内部的函数名不要以下划线开头。 > Why? Underscore prefixes are sometimes used as a convention in other languages to denote privacy. But, unlike those languages, there is no native support for privacy in JavaScript, everything is public. Regardless of your intentions, adding underscore prefixes to your properties does not actually make them private, and any property (underscore-prefixed or not) should be treated as being public. See issues #1024, and #490 for a more in-depth discussion.

    // bad
    React.createClass({
      _onClickSubmit() {
        // do stuff
      },
    
      // other stuff
    });
    
    // good
    class extends React.Component {
      onClickSubmit() {
        // do stuff
      }
    
      // other stuff
    }
  • Be sure to return a value in your render methods. eslint: react/require-render-return

    render 中必须有 return 方法。

    // bad
    render() {
      (<div />);
    }
    
    // good
    render() {
      return (<div />);
    }

Ordering

  • Ordering for class extends React.Component:

  • optional static methods

  • constructor
  • getChildContext
  • componentWillMount
  • componentDidMount
  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate
  • componentDidUpdate
  • componentWillUnmount
  • clickHandlers or eventHandlers like onClickSubmit() or onChangeDescription()
  • getter methods for render like getSelectReason() or getFooterContent()
  • optional render methods like renderNavigation() or renderProfilePicture()
  • render

  • How to define 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;
  • Ordering for React.createClass: eslint: react/sort-comp

  • displayName

  • propTypes
  • contextTypes
  • childContextTypes
  • mixins
  • statics
  • defaultProps
  • getDefaultProps
  • getInitialState
  • getChildContext
  • componentWillMount
  • componentDidMount
  • componentWillReceiveProps
  • shouldComponentUpdate
  • componentWillUpdate
  • componentDidUpdate
  • componentWillUnmount
  • clickHandlers or eventHandlers like onClickSubmit() or onChangeDescription()
  • getter methods for render like getSelectReason() or getFooterContent()
  • optional render methods like renderNavigation() or renderProfilePicture()
  • render

isMounted

Why? isMounted is an anti-pattern, is not available when using ES6 classes, and is on its way to being officially deprecated.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值