React / JSX規範

基本規則

  • 每個文件只包含一個React組件。
  • 始終使用JSX語法。
  • React.createElement除非您從不是JSX的文件初始化應用程序,否則請勿使用。

Class vs React.createClass vs stateless

  • If you have internal state and/or refs, prefer class extends React.Component over React.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>;
    }

命名

  • 擴展:使用.jsxReact組件的擴展。

  • 文件名:使用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應該產生一個組分與displayNamewithFoo(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在元素上使用。

避免使用數組索引作爲keyprop,更喜歡穩定的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 />);
    }
  • 如何定義 propTypesdefaultPropscontextTypes, 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開發時遵循的一些語法規範。如有不足之處,歡迎大家給出建議!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章