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
import reservationCard from './ReservationCard'
import ReservationCard from './ReservationCard'
const ReservationItem = <ReservationCard />
const reservationItem = <ReservationCard />
|
使用文件名作为组件名字,例如, ReservationCard.js
应该包含名为 ReservationCard
的引用,然而对于文件夹中的根组件, 使用 index.js
作为文件名,使用文件夹的名字作为组件的名字
import Footer from './Footer/Footer'
import Footer from './Footer/index'
import Footer from './Footer'
|
React DOM 使用小驼峰式命名法来定义属性的名称,而不使用 HTML 属性名称的命名约定,例如
<div onClick={this.handler} />
|
Class Component VS Functional Component
只允许使用 Class Component
和 Functional Component
两种形态来书写组件,建议尽量使用函数式组件配合 Hooks 来进行开发
对齐
遵循以下JSX语法的对齐风格,eslint: react/jsx-closing-bracket-location
<Foo superLongParam='bar' anotherSuperLongParam='baz' />
<Foo superLongParam='bar' anotherSuperLongParam='baz' />
<Foo bar='bar' />
<Foo superLongParam='bar' anotherSuperLongParam='baz' > <Quux /> </Foo>
// bad {showButton && <Button /> }
{ showButton && <Button /> }
{showButton && ( <Button /> )}
{showButton && <Button />}
|
空格
<Foo/>
<Foo />
<Foo />
<Foo />
|
<Foo bar={ baz } />
<Foo bar={baz} />
|
引号
JSX 属性要使用单引号,与其他普通 JS 保持一致
<Foo bar="bar" />
<Foo bar='bar' />
<Foo style={{ left: "20px" }} />
<Foo style={{ left: '20px' }} />
|
属性
<Foo UserName='hello' phone_number={12345678} />
<Foo userName='hello' phoneNumber={12345678} />
|
<Foo hidden={true} />
<Foo hidden />
<Foo hidden />
|
原因:不使用稳定的 ID 会对性能产生副作用并且组件状态会出问题,是一种反模式
{todos.map((todo, index) => <Todo {...todo} key={index} /> )}
{todos.map(todo => ( <Todo {...todo} key={todo.id} /> ))}
|
- 为所有的非必需属性定义使用 defaultProps 明确的默认值
function SFC ({ foo, bar, children }) { return <div>{foo}{bar}{children}</div> } SFC.propTypes = { foo: PropTypes.number.isRequired, bar: PropTypes.string, children: PropTypes.node }
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 }
|
Refs
避免使用字符串引用,请使用回调函数作为引用,eslint: react/no-string-refs
<Foo ref='myRef' />
<Foo ref={ref => { this.myRef = ref }} />
|
圆括号
当 JSX 标签超过一行时使用圆括号包裹, eslint: react/wrap-multilines
render () { return <MyComponent className='long body' foo='bar'> <MyChild /> </MyComponent> }
render () { return ( <MyComponent className='long body' foo='bar'> <MyChild /> </MyComponent> ) }
// good, when single line render () { const body = <div>hello</div> return <MyComponent>{body}</MyComponent> }
|
标签
<Foo className='stuff'></Foo>
// good <Foo className='stuff' />
|
<Foo bar='bar' baz='baz' />
<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> ) }
|
class extends React.Component { _onClickSubmit () { }
}
class extends React.Component { onClickSubmit () { }
}
|
render () { (<div />) }
render () { return (<div />) }
|
Hooks 书写规范
Hooks 只能应用于函数式组件中
只在 React 函数最顶层使用 Hooks
不要在循环,条件或嵌套函数中调用 Hook, 确保总是在你的 React 函数的最顶层调用他们
function a () { const [count, setCount] = useState(0) useEffect(function persistForm() { localStorage.setItem('formData', accountName) }) const x = function () {} const [timer, setTimer] = useState(0)
}
function a () { const [count, setCount] = useState(0) useEffect(function persistForm() { localStorage.setItem('formData', accountName) }) const [timer, setTimer] = useState(0) const x = function () {} }
|