使用 Typescript
Typescript 能够提供很好的代码检查功能,配合 vscode 在开发阶段就能第一时间洞悉语法错误。
使用 Function component
只在少数特殊情况下使用 class component
不使用 React.FC
// bad
export const Button: React.FC<ButtonProps> = (props) => {
...
}
// good
export const Button = (props: ButtonProps) => {
...
}
// good
export const Button = ({type, size, ...restProps}: ButtonProps) => {
...
}
原因出处:
- https://github.com/facebook/create-react-app/pull/8177
- https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/function_components/
不使用 prop-types
虽然 prop-types
和 typescript
不是完全的对等,但是完全没有必要在 typescript
项目中使用 prop-types
。
不使用 defaultProps
// bad
Button.defaultProps = {
type: 'default',
size: 'middle',
};
// good
export const Button = ({type = 'default', size = 'middle', ...restProps}: ButtonProps) => {
...
}
原因出处:
- https://github.com/facebook/react/pull/16210
- https://react-typescript-cheatsheet.netlify.app/docs/basic/getting-started/default_props/
不使用 enum
type
更方便进行扩展,书写时也能方便进行提示。
// bad
enum ButtonSize {
LARGE = 'large',
MIDDLE = 'middle',
SMALL = 'small',
}
// good
type ButtonSize = 'large' | 'middle' | 'small';
// Extensible:
type ExtendedButtonSize = ButtonSize | 'mini';
不使用第三方库
- 第三方库的代码质量参差不齐不可控
- 滥用第三方库会导致打包体积变大
- 新手可能因为依赖第三方库而能力得不到提高
如果特殊情况下,不得不使用第三方库,必须经过 Review
使用 CSS 变量
css
变量提供了更加动态化的样式调整能力,也让组件的样式调整变得更加简洁优雅。
// bad
.ud-button {
color: #7284fb;
}
// bad
.ud-button {
color: var(--ud-color-primary);
}
// good
.ud-button {
color: $button-color-primary;
}
// variables.scss
$button-color-primary: var(--ud-button-color-primary, var(--ud-color-primary)); // 默认态按钮主要色
使用 CSS 变量接口
开发组件时,需要考虑组件样式的扩展性,使用 var
对外暴露 CSS
变量接口,禁止写死属性。
// bad
$button-color-primary: #7284fb; // 默认态按钮主要色
// good
$button-color-primary: var(--ud-button-color-primary, var(--ud-color-primary)); // 默认态按钮主要色
使用组件拆分
必须对组件进行拆分,以增加代码的可阅读性和可维护性。下面是一个 Input 组件:
const renderPrepend = () => {...}
const renderPrefix = () => {...}
const renderInput = () => {...}
const renderClearBtn = () => {...}
const renderCount = () => {...}
const renderPasswordBtn = () => {...}
const renderSuffix = () => {...}
const renderAppend = () => {...}
...
使用 NativeProps
所有组件统一使用 NativeProps
来支持 style
, className
和 children
属性。
import { NativeProps } from '../../utils';
export type ButtonProps = {
...
} & NativeProps;
使用 name
统一使用 name
来作为组件的唯一标志符,不使用 activeKey
的原因是方便书写。
export type ItemProps = {
name: string; // 唯一标志符
// ...
} & NativeProps;
编写测试
最佳实践是将测试文件命名为 componentName.test.js
,这样会很方便查找。
推荐使用 Jest + React Testing Library,enzyme 已不推荐使用。
使用代码校验
应该强制在 commit 之前做 lint 检查,可以在 package.json 中添加 precommit 脚本
"scripts": {
"precommit": "npm run lint",
"lint": "npm run lint:js && npm run lint:style",
"lint:js": "eslint --cache --ext .js,.jsx,.ts,.tsx --format=pretty ./src",
"lint:style": "stylelint --fix \"src/**/*.less\" --syntax less",
......
}
或者使用 lint-stage 只校验本次修改涉及的代码。
"lint-staged": {
"apps/**/*.{js,jsx,ts,tsx}": [
"eslint --ext '.js,.jsx,.ts,.tsx'"
],
"packages/**/*.{js,jsx,ts,tsx}": [
"eslint --ext '.js,.jsx,.ts,.tsx'"
]
},
同一个组件的所有文件放在一起
将同一个组件的所有相关文件放在同一个目录下,css 和 js 放在同级目录下,比如 Comment 组件可以这样:
/components/Comment/CommentForm/index.less
/components/Comment/CommentForm/index.tsx
/components/Comment/CommentList/index.less
/components/Comment/CommentList/index.tsx
/components/Comment/CommentItem/index.less
/components/Comment/CommentItem/index.tsx
/components/Comment/index.less
/components/Comment/index.ts
/containers/Comment/index.less
/containers/Comment/index.tsx
并且在 /components/Comment/index.ts
里 export 所有子组件。
区分有无状态组件
React 官方建议:多写无状态组件;组件最小粒度化;组件只是数据的管道工!
无状态组件
相同输入,相同输出,没有副作用; 负责 render markup and styles, read data from props and invoke callbacks from props. 这种组件应该放在**/components**目录下。
有状态组件
相同输入,不一定相同输出,还可能修改外部的值; 负责 data fetching, dispatch actions, 直接与 redux 等交互。几乎没有 HTML 标签,除了一个容器 div。 这种组件应该放在**/containers**目录下。
https://stackoverflow.com/questions/43414254/difference-between-component-and-container-in-react-redux
使用 hooks
在 React 16.8 版本之后,逻辑的复用,无论是 container 还是 component 都可以复用逻辑,这部分代码应该使用自定义 hooks,并且放在**/hooks**目录下。
核心:state 最小粒度,是 React 的最佳实践。
最终 src 目录结构
- assets
- /components
- /Comment
- /CommentForm
- index.less
- index.tsx
- /CommentList
- index.less
- index.tsx
- /CommentItem
- index.less
- index.tsx
- index.less
- index.ts
- /CommentForm
- /Comment
- /containers
- /Comment
- index.less
- index.tsx
- /Comment
- /hooks
- /layouts
- /locales
- /models
- comment.ts
- /pages
- /services
- comment.ts
- /utils
- utils.js
- utils.test.js
- app.ts
- global.less
- global.ts
- manifest.json
参考
https://onesignal.com/blog/effective-typescript-for-react-applications/ https://www.codeinwp.com/blog/react-best-practices/