React&JSX 书写规范

React&JSX 书写规范

本规范基本基于标准的 JavaScript 语法规范

基本规则

  • 每个文件只包含一个 React 类组件
  • 一般使用 JSX 语法
  • 除非是在非 JSX 文件中初始化应用,否则不要使用 React.createElement

命名规范

  • 组件文件扩展名

如果使用 JavaScript,则文件扩展名为 .js;如果使用 TypeScript,则文件扩展名为 .tsx

  • 组件文件名

如果是组件文件,则使用 PascalCase,如 MyComponent.js

如果组件是一个目录,则组件主入口命名为 index,如 index.js

  • 引用命名

React 组件使用 PascalCase,组件实例使用 CamelCase,eslint: react/jsx-pascal-case

  1. // bad
  2. import reservationCard from './ReservationCard'
  3. // good
  4. import ReservationCard from './ReservationCard'
  5. // bad
  6. const ReservationItem = <ReservationCard />
  7. // good
  8. const reservationItem = <ReservationCard />
  • 组件命名

使用文件名作为组件名字,例如, ReservationCard.js 应该包含名为 ReservationCard 的引用,然而对于文件夹中的根组件, 使用 index.js 作为文件名,使用文件夹的名字作为组件的名字

  1. // bad
  2. import Footer from './Footer/Footer'
  3. // bad
  4. import Footer from './Footer/index'
  5. // good
  6. import Footer from './Footer'
  • 组件属性名

React DOM 使用小驼峰式命名法来定义属性的名称,而不使用 HTML 属性名称的命名约定,例如

  1. <div onClick={this.handler} />

Class Component VS Functional Component

只允许使用 Class ComponentFunctional Component 两种形态来书写组件,建议尽量使用函数式组件配合 Hooks 来进行开发

对齐

遵循以下JSX语法的对齐风格,eslint: react/jsx-closing-bracket-location

  1. // bad
  2. <Foo superLongParam='bar'
  3. anotherSuperLongParam='baz' />
  4. // good
  5. <Foo
  6. superLongParam='bar'
  7. anotherSuperLongParam='baz'
  8. />
  9. // if props fit in one line then keep it on the same line
  10. <Foo bar='bar' />
  11. // children get indented normally
  12. <Foo
  13. superLongParam='bar'
  14. anotherSuperLongParam='baz'
  15. >
  16. <Quux />
  17. </Foo>
  18. // bad
  19. {showButton &&
  20. <Button />
  21. }
  22. // bad
  23. {
  24. showButton &&
  25. <Button />
  26. }
  27. // good
  28. {showButton && (
  29. <Button />
  30. )}
  31. // good
  32. {showButton && <Button />}

空格

  1. // bad
  2. <Foo/>
  3. // very bad
  4. <Foo />
  5. // bad
  6. <Foo
  7. />
  8. // good
  9. <Foo />
  1. // bad
  2. <Foo bar={ baz } />
  3. // good
  4. <Foo bar={baz} />

引号

JSX 属性要使用单引号,与其他普通 JS 保持一致

  1. // bad
  2. <Foo bar="bar" />
  3. // good
  4. <Foo bar='bar' />
  5. // bad
  6. <Foo style={{ left: "20px" }} />
  7. // good
  8. <Foo style={{ left: '20px' }} />

属性

  • 属性名使用 CamelCase
  1. // bad
  2. <Foo
  3. UserName='hello'
  4. phone_number={12345678}
  5. />
  6. // good
  7. <Foo
  8. userName='hello'
  9. phoneNumber={12345678}
  10. />
  1. // bad
  2. <Foo
  3. hidden={true}
  4. />
  5. // good
  6. <Foo
  7. hidden
  8. />
  9. // good
  10. <Foo hidden />

原因:不使用稳定的 ID 会对性能产生副作用并且组件状态会出问题,是一种反模式

  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. ))}
  • 为所有的非必需属性定义使用 defaultProps 明确的默认值
  1. // bad
  2. function SFC ({ foo, bar, children }) {
  3. return <div>{foo}{bar}{children}</div>
  4. }
  5. SFC.propTypes = {
  6. foo: PropTypes.number.isRequired,
  7. bar: PropTypes.string,
  8. children: PropTypes.node
  9. }
  10. // good
  11. function SFC ({ foo, bar, children }) {
  12. return <div>{foo}{bar}{children}</div>
  13. }
  14. SFC.propTypes = {
  15. foo: PropTypes.number.isRequired,
  16. bar: PropTypes.string,
  17. children: PropTypes.node
  18. }
  19. SFC.defaultProps = {
  20. bar: '',
  21. children: null
  22. }

Refs

避免使用字符串引用,请使用回调函数作为引用,eslint: react/no-string-refs

  1. // bad
  2. <Foo
  3. ref='myRef'
  4. />
  5. // good
  6. <Foo
  7. ref={ref => { this.myRef = ref }}
  8. />

圆括号

当 JSX 标签超过一行时使用圆括号包裹, eslint: react/wrap-multilines

  1. // bad
  2. render () {
  3. return <MyComponent className='long body' foo='bar'>
  4. <MyChild />
  5. </MyComponent>
  6. }
  7. // good
  8. render () {
  9. return (
  10. <MyComponent className='long body' foo='bar'>
  11. <MyChild />
  12. </MyComponent>
  13. )
  14. }
  15. // good, when single line
  16. render () {
  17. const body = <div>hello</div>
  18. return <MyComponent>{body}</MyComponent>
  19. }

标签

  1. // bad
  2. <Foo className='stuff'></Foo>
  3. // good
  4. <Foo className='stuff' />
  1. // bad
  2. <Foo
  3. bar='bar'
  4. baz='baz' />
  5. // good
  6. <Foo
  7. bar='bar'
  8. baz='baz'
  9. />

方法

  • 使用箭头函数包裹本地变量
  1. function ItemList (props) {
  2. return (
  3. <ul>
  4. {props.items.map((item, index) => (
  5. <Item
  6. key={item.key}
  7. onClick={() => doSomethingWith(item.name, index)}
  8. />
  9. ))}
  10. </ul>
  11. )
  12. }
  • 类组件的内部方法不要使用下划线前缀
  1. // bad
  2. class extends React.Component {
  3. _onClickSubmit () {
  4. // do stuff
  5. }
  6. // other stuff
  7. }
  8. // good
  9. class extends React.Component {
  10. onClickSubmit () {
  11. // do stuff
  12. }
  13. // other stuff
  14. }
  1. // bad
  2. render () {
  3. (<div />)
  4. }
  5. // good
  6. render () {
  7. return (<div />)
  8. }

Hooks 书写规范

  • Hooks 只能应用于函数式组件中

  • 只在 React 函数最顶层使用 Hooks

不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层调用他们

  1. // bad
  2. function a () {
  3. const [count, setCount] = useState(0)
  4. useEffect(function persistForm() {
  5. localStorage.setItem('formData', accountName)
  6. })
  7. const x = function () {}
  8. const [timer, setTimer] = useState(0)
  9. // main logic
  10. }
  11. // bad
  12. function a () {
  13. const [count, setCount] = useState(0)
  14. useEffect(function persistForm() {
  15. localStorage.setItem('formData', accountName)
  16. })
  17. const [timer, setTimer] = useState(0)
  18. const x = function () {}
  19. // main logic
  20. }