准备
项目地址,项目会持续进行更新,文档会和项目同步更新
项目初始化
全局安装 react 的脚手架
npm i -g create-react-app
使用脚手架创建项目,语言使用ts
create-react-app react-demo --template typescript
使用eject命令,将所有的配置导出,可以进行项目的自定义操作,记住操作是不可逆的
npm run eject
启动项目
npm start
项目创建完成
将项目推到远端的git 仓库
echo "# react-demo" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin https://github.com/XXX/react-demo.git
git push -u origin main
组件库
先安装一个antd的组件库
npm install antd --save
React Router 安装命令如下。
npm install react-router-dom
注意如果在 web 上的话,你需要的是 react-router-dom
而不是 react-router
这个包。它们的区别是,后者包含了 react-native
中需要的一些组件,如果你只需要做网页应用的话,用前者就可以了
项目接入规范
ESlint
其中ESlint可以保证我们的代码质量,可以检查我们的代码质量并给出最终的报告。
当前的项目主要使用采用 eslint-config-airbnb
来配置,我们风格和他们保持一致,这份规范是使用度比较高的配置。
安装相关的依赖包,我们说明一下这些包的作用
- eslint-plugin-import:此插件主要为了校验
import/export
语法,防止错误拼写文件路径以及导出名称的问题 - eslint-plugin-react:校验 React
- eslint-plugin-react-hooks:根据 Hooks API 校验 Hooks 的使用
npm i -D eslint-config-airbnb eslint-plugin-import eslint-plugin-react eslint-plugin-react-hooks
具体的.eslintrc.js
配置如下
module.exports = {
// 为我们提供运行环境,一个环境定义了一组预定义的全局变量
env: {
browser: true,
es6: true,
},
// 一个配置文件可以被基础配置中的已启用的规则继承。
extends: ['airbnb'],
// 自定义全局变量
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly',
_: true,
$: true,
},
settings: {
'import/resolver': {
node: {
extensions: ['.js', '.jsx', '.ts', '.tsx'],
},
},
},
// ESLint 默认使用Espree作为其解析器,你可以在配置文件中指定一个不同的解析器
// "parser": "@typescript-eslint/parser",
// 配置解析器支持的语法
parserOptions: {
ecmaFeatures: {
jsx: true,
},
ecmaVersion: 2018,
sourceType: 'module',
},
// ESLint 支持使用第三方插件。在使用插件之前,你必须使用 npm 安装它。
// 在配置文件里配置插件时,可以使用 plugins 关键字来存放插件名字的列表。插件名称可以省略 eslint-plugin- 前缀。
plugins: [
'react',
// "@typescript-eslint"
],
// ESLint 附带有大量的规则。你可以使用注释或配置文件修改你项目中要使用的规则。要改变一个规则设置,你必须将规则 ID 设置为下列值之一:
// "off" 或 0 - 关闭规则
// "warn" 或 1 - 开启规则,使用警告级别的错误:warn (不会导致程序退出)
// "error" 或 2 - 开启规则,使用错误级别的错误:error (当被触发的时候,程序会退出)
rules: {
semi: 0,
'no-unused-vars': [
1,
{
vars: 'all',
args: 'after-used',
ignoreRestSiblings: true,
varsIgnorePattern: '^_',
argsIgnorePattern: '^_|^err|^ev', // _xxx, err, error, ev, event
},
],
'no-useless-escape': 2,
quotes: [0, 'double'],// 项目默认使用双引号
// 解决eslint 的一些报错问题
'import/extensions': [
'error',
'ignorePackages',
{
js: 'never',
jsx: 'never',
ts: 'never',
tsx: 'never',
},
],
'react/jsx-filename-extension': [1, { extensions: ['.js', '.jsx', '.tsx'] }],
'react/function-component-definition': 'off', // 规则禁用
'object-curly-newline': 'off', // 规则禁用
},
};
在package.json 中我们可以配置相关的命令脚本,当执行脚本的时候全局执行代码检查,判断哪些代码是存在问题的。
Prettier
我们使用ESlint
来保证代码质量,需要使用Prettier
来保证代码的风格,我们也需要安装相关的包,来完成项目配置。
npm i -D prettier eslint-config-prettier eslint-plugin-prettier
我们需要在.eslintrc.js
中需要添加文件的内容,兼容这部分的内容:
"extends": [
"airbnb",
"plugin:prettier/recommended"
]
增加 prettier 配置文件,在根目录创建 .prettierrc.js
:
module.exports = {
printWidth: 120, //一行的字符数,如果超过会进行换行,默认为80
tabWidth: 2, //一个tab代表几个空格数,默认为2
};
提交代码
我们需要保证项目的规范确实使用,我们需要配置husky,lint-staged,保证项目在提交到git 上面的时候是正确的,我们也需要安装这包。
- husky,一款管理
git hooks
的工具,以此来增强git功能 - commitlint,一款
git commit
提交规范检验工具,结合commit-msg钩子,实现提交规范的校验 - lint-staged,一个对
git暂存区
代码进行处理的工具,结合pre-commit钩子,实现对暂存区文件的校验
husky
当前使用的husky为9版本,安装和使用方法和之前稍显不同:
npm install husky -D
执行命令如下
npx husky init
添加钩子:
echo "npm test" > .husky/pre-commit
commitlint
我们需要安装,御用对提交信息的 message
规范进行校验。
- @commitlint/config-conventional 是基于
conventional commits
规范的配置文件。 - @commitlint/cli 是
commitlint
工具的核心。
npm install -D commitlint @commitlint/cli @commitlint/config-conventional
对于进行配置,增加 .commitlintrc.js
配置文件
module.exports = {
extends: ['@commitlint/config-conventional']
};
然后结合husky
,实现git commit
的规范验证,执行命令:
echo "npx --no-install commitlint -e $HUSKY_GIT_PARAMS" > .husky/commit-msg
这个时候会在.husky/commit-msg
的文件中的内容会变成如下的内容
npx --no-install commitlint -e
lint-staged
npm install lint-staged -D
在package.json
添加如下的配置:
{
"scripts": [
"lint-staged": "lint-staged"
],
"lint-staged": {
"*.{js,ts,jsx,tsx}": [
"eslint --fix"
]
},
}
结合husky,实现对暂存区文件的校验
echo "npm run lint-staged" > .husky/pre-commit
其中当前的文件.husky/pre-commit
的内容为
npm run lint-staged
接入react-router
文档参考,比较好的诠释了react-router6的特性
先进行最简单的路由实践,我们在app.tsx 文件中只做最简单的路由实践:Route
组件用于将应用的位置映射到不同的 React 组件,要在所有 Route
都不匹配时就渲染 404 页面,只需将 404 页面对应的 Route
的 path
设置为 *
:
import React from 'react';
import { Routes, Route, BrowserRouter } from 'react-router-dom';
import About from './pages/About';
import Test from './pages/Test';
import './App.css';
const App = () => (
<BrowserRouter>
<Routes>
<Route path="/" element={<About />} />
<Route path="/Test" element={<Test />} />
</Routes>
</BrowserRouter>
);
export default App;
最新的版本我们可以使用useRoutes
的方式来定义路由,具体的写法如下:
import React from 'react';
import About from '../pages/About';
import About1 from '../pages/About1';
import Test from '../pages/Test';
import { useRoutes } from 'react-router-dom';
import routes from './router/router';
import './App.css';
const routes = [
{ path: '/about', element: <About /> },
{
path: '/test',
element: <Test />,
},
{
path: '/About1',
element: <About1 />,
},
];
const App = () => {
const routesShow = useRoutes(routes);
return <div>{routesShow}</div>;
};
export default App;
当我们需要点击的时候进行路由跳转的时候,代码如下:
import React from 'react';
import { Badge } from 'antd';
import { useNavigate } from 'react-router-dom';
const HomePage = () => {
const navigate = useNavigate();
const handleRouterGo = (key: string) => {
navigate('/test'); // 输入path
};
return (
<div className="homePageWrapper">
<div className="desc-item" key={item.key} onClick={() => handleRouterGo(item.key)}/>
);
};
export default HomePage;
代码片段
我在写函数组件的时候,比较喜欢使用箭头函数的,但是现在市面上的代码片段,函数的声明方式都是使用function
,所以我决定自己来写一些简单的代码片段,推荐一个网站,这个网站方便我们写代码片段,由于书写代码片段很麻烦,每一行都要加双引号
这些,所以推荐一个网站,将需要变为代码片段的代码转化为这种格式。
为项目写的配置文件如下:
{
"new function component": {
"prefix": "nfc",
"body": [
"import React, { useState } from 'react';",
"import './index.scss';",
"",
"const page = () => {",
" const [state, setState] = useState(0);",
" return <div className=\"\"></div>;",
"};",
"",
"export default page;",
"",
],
"description": "new function component",
},
}
配置别名
在webpack的配置文件中添加配置
alias: {
'@': path.resolve(__dirname, '../src'),
'@BusinessComponent': path.resolve(__dirname, '../src/BusinessComponent'), // 新增加的配置
}
但是由于我们使用的语言是TypeScript
语言,导致我们还需要在tsconfig.json
中进行相关的配置,解决配置的问题,我们的配置很简单
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@BusinessComponent/*": [
"./src/BusinessComponent/*"
]
},
}
这样我们就解决了我们在import
的时候引用的路径过长的问题。
在线编辑
因为是组件库,所以我们需要实现组件在线编辑,而不是像antd一样需要跳转到sandbox才可以完成编辑,所以我们需要一个轻量级的编辑组件。先简单的写一个最简单的例子,不考虑样式,对于组件的封装如下:
import React from 'react';
import * as antd from 'antd';
import { LiveProvider, LiveEditor, LivePreview } from 'react-live';
import './index.scss';
const scope = { ...antd };
const Editor = (props: any) => {
const { code } = props;
return (
<div className="live-card">
<LiveProvider code={code} scope={scope} noInline>
<div className="preview">
<LivePreview />
</div>
<LiveEditor className="font-mono" />
</LiveProvider>
</div>
);
};
export default Editor;
我们传入的方式如下:
import React, { useState } from 'react';
import Editor from 'src/BusinessComponent/Editor';
import './index.scss';
const jsxExample = `
const ButtonShow = () => {
return (
<div >
<Button >999</Button>
</div>
);
};
render(<ButtonShow></ButtonShow>)
`;
const ButtonShow = () => {
const [state, setState] = useState(0);
return (
<div className="">
<Editor code={jsxExample} />
</div>
);
};
export default ButtonShow;
接入单元测试
Jest的官网路径
我们使用jest
进行函数的单元测试,使用断言等方式对组件进行自动化测试,并生成测试报告。我使用的脚手架已经提供了jest
大家若是没有jest,可以自己安装一下,安装命令如下:
npm install jest -D
我们可以在util中进行一些简单的公共方法的测试,验证公共方法的正确性,后续在修改公共方法的时候,可以跑一下测试用例,保证边界值的正确性。
// math.test.ts
import { add } from './math';
describe('测试add', function () {
test('测试1+1', function () {
expect(add(1, 1)).toBe(2);
});
test('测试2+2', function () {
expect(add(2, 2)).toBe(4);
});
test('测试2+9', function () {
expect(add(2, 2)).toBe(4);
});
});
公共方法的写法:
// math.test.ts
const add = (a: number, b: number) => {
return a + b;
};
export { add };
在package.json 配置跑的命令如下:
"scripts": {
"test": "node scripts/test.js",
"coverage": "node scripts/test.js --coverage", // 查看测试报告,查看测试用例覆盖率等指标
}
类型 | 说明 |
---|---|
line coverage | 行覆盖率 |
function coverage | 函数覆盖率 |
branch coverage | 分支覆盖率 |
statement coverage | 语句覆盖率 |
我们需要配合UI进行单元测试,所以我们还需要一些其他的库进行配合单元测试,之前使用的单元测试的包为enzyme
,现在我们一般使用@testing-library/react
进行测试,假设我们对公共的业务组件进行测试,具体的流程如下:
我们具体的Header
组件的代码如下:
import React from 'react';
import { useNavigate } from 'react-router-dom';
import imgURL from '../../assets/header.png';
import gitUrl from '../../assets/git.jpeg';
import { tabConfig } from './config';
import './index.scss';
const Header = () => {
const navigate = useNavigate();
const handleClick = (url: string) => {
navigate(url);
};
const gotoGitPage = () => {
window.open('https://github.com/KimQueen/react-project');
};
return (
<div className="warpContent-header">
<div className="left">
<img src={imgURL} alt="图标" className="imgStyle" />
<div className="title">Component</div>
</div>
<div className="content" />
<div className="right">
{tabConfig.map((item) => (
<div key={item.name} onClick={() => handleClick(item.url)} className="tabItem">
{item.name}
</div>
))}
<div onClick={() => gotoGitPage()}>
<img src={gitUrl} className="gitImg" alt="git" />
</div>
</div>
</div>
);
};
export default Header;
我们需要对于这个组件进行快照抓取,我们具体的header.test.js
如下:
import '@testing-library/jest-dom';
import { render } from '@testing-library/react';
import Header from '../Header';
const mockUsedNavigate = jest.fn();
jest.mock('react-router-dom', () => ({
...jest.requireActual('react-router-dom'),
useNavigate: () => mockUsedNavigate,
}));
describe('Header', () => {
test('renders Header component, give snapshots', () => {
const { asFragment } = render(<Header />);
expect(asFragment()).toMatchSnapshot();
});
});
写好后我们再跑test的命令得到的快照如下:
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`Header renders Header component 1`] = `
<DocumentFragment>
<div
class="warpContent-header"
>
<div
class="left"
>
<img
alt="图标"
class="imgStyle"
src="header.png"
/>
<div
class="title"
>
Component
</div>
</div>
<div
class="content"
/>
<div
class="right"
>
<div
class="tabItem"
>
首页
</div>
<div
class="tabItem"
>
关于
</div>
<div
class="tabItem"
>
联系我们
</div>
<div>
<img
alt="git"
class="gitImg"
src="git.jpeg"
/>
</div>
</div>
</div>
</DocumentFragment>
`;
react-testing-library官方网址相关文档可以再这里进行查看