码农之家

从零搭建一个 React 应用

使用 cd React App 创建应用

Create React App 官网地址 create-react-app.bootcss.com

使用下面命令创建一个 React 应用,使用的是默认的模板。

npx create--react-app myapp
# or 使用 typescript 模板
npx create-react-app myapp --template typescript

可以通过 --template 可以指定我们想要下载的模板,这里我使用 typescript 模板,我们也可以使用我们自己创建的模板,模板开发可以参考 create-react-app.dev/docs/custom…

然后进入的项目目录下,执行 npm start 启动项目

cb myapp
npm install

配置 eslint

初始化 eslint

安装 eslint

npm init @eslint/config

选择下面配置

✔ How would you like to use ESLint? · problems
✔ What type of modules does your project use? · esm
✔ Which framework does your project use? · react
✔ Does your project use TypeScript? ·  Yes
✔ Where does your code run? · browser
✔ What format do you want your config file to be in? · JavaScript

这里没有使用 eslint 校验代码格式,因为 eslint 无法格式化我们的 jsx 代码片段,使用 prettier 可以格式化 tsx 文件中的所有代码

prettier

prettier 配置到 eslint 中

npm i prettier eslint-config-prettier  eslint-plugin-prettier -D

编写 prettier 配置文件

module.exports = {
  // 箭头函数只有一个参数的时候可以忽略括号
  arrowParens: 'avoid',
  // 括号内部不要出现空格
  bracketSpacing: true,
  // 行结束符使用 Unix 格式
  endOfLine: 'lf',
  // true: Put > on the last line instead of at a new line
  jsxBracketSameLine: false,
  // 行宽
  printWidth: 100,
  // 换行方式
  proseWrap: 'preserve',
  // 分号
  semi: false,
  // 使用单引号
  singleQuote: true,
  // 缩进
  tabWidth: 2,
  // 使用 tab 缩进
  useTabs: false,
  // 后置逗号,多行对象、数组在最后一行增加逗号
  trailingComma: 'es5',
  parser: 'typescript',
}

prettier 添加到 eslint 配置文件中。相关参考文档 prettier.io/docs/en/con…

/* eslint-env node */
module.exports = {
  env: {
    browser: true,
    es2021: true,
  },
  extends: [
    'eslint:recommended',
    'plugin:react/recommended',
    'plugin:@typescript-eslint/recommended',
    'plugin:prettier/recommended',
  ],
  overrides: [],
  parser: '@typescript-eslint/parser',
  parserOptions: {
    ecmaVersion: 'latest',
    sourceType: 'module',
  },
  plugins: ['react', '@typescript-eslint'],
  rules: {},
}

eslint 相关配置参考文档 eslint.org/docs/latest…

编辑器配置(vscode)

配置 vscode

  • 安装 eslint 插件
  • 安装 prettier 插件
  • 编辑器配置使用 prettier 格式化 ts、tsx 代码
// .vscode/settings.json
{
    "editor.tabSize": 2,
    "[tsx,ts]": {
	  	"editor.defaultFormatter": "esbenp.prettier-vscode"
    },
    "editor.formatOnSave": true
}

配置代理

开发过程中可能会遇到跨域问题,可以通过配置代理进行解决

方式一

方式就是直接在 package.json 文件中配置。任何没有意义的请求都会代理到指定的 proxy

{
    "proxy": "http://localhost:3001",
}

但这种方式的缺点就不够灵活

方式二

npm i http-proxy-middleware

创建文件 src/setupProxy.js

const { createProxyMiddleware } = require('http-proxy-middleware')

module.exports = function (app) {
  // 注册代理,可以注册多个代理
  app.use(
    '/api',
    createProxyMiddleware({
      target: 'http://localhost:3001',
      changeOrigin: true,
    })
  )
  // 注册代理
   app.use(
    '/api2',
    createProxyMiddleware({
      target: 'http://localhost:8001',
      changeOrigin: true,
    })
  )
  ...
}

注意 这里不能只能使用 js 文件,不支持使用 ts 文件

Mock 数据

开发过程中,如果后端的接口还没有写好,我们不可能等到后端接口写好才开始写,这时,我们就需要 mock 数据了,在这之前,前后端需要约定好数据的格式。这里使用 mockjs,需要先了解下 mockjs 的使用。github.com/nuysoft/Moc…

这里我们使用 koa 搭建 mock 服务器,也可以使用 express 、 fastify 等。这里有一个使用 fastify 的例子 github.com/shibin-cli/…

npm init -y
npm i koa @koa/router mockjs koa-body typescript ts-node
tsc --init

使用 koa 搭建 mock 服务器

import Koa from 'koa'
import Router from '@koa/router'
import { koaBody } from 'koa-body'
import mocklist from './mock' // 我们准备的路由和mock数据

const app = new Koa()
const router = new Router({
  prefix: '/api',
})
app.use(koaBody())

function sleep(second: number) {
  return new Promise(resolve => {
    setTimeout(resolve, 1000 * second)
  })
}
mocklist.forEach(item => {
  const { url, method, response } = item
  router[method](url, async ctx => {
    // 这里是为了测试前端的 loading 效果、重复点击等
    await sleep(0.5)
    ctx.body = response(ctx)
  })
})

app.use(router.routes()).use(router.allowedMethods())
app.listen(3001)

准备我们的路由

import Mock from 'mockjs'

export interface MockItem {
  method: Method
  url: string
  response: (ctx: Koa.ParameterizedContext<Koa.DefaultState, Koa.DefaultContext, any>) => MockRes
}

const Random = Mock.Random
const userMock: MockItem[] = [
  {
    url: '/user',
    method: 'get',
    response(ctx) {
      const { user } = ctx.state
      return {
        errno: 0,
        data: {
          username: user.username,
          id: user.id,
          nickname: Random.cname(),
        },
      }
    },
  },
  {
    url: '/login',
    method: 'post',
    response(ctx) {
      const { username } = ctx.request.body
      return {
        errno: 0,
        data: {
          token: Random.id(),
        },
      }
    },
  },
  {
    url: '/register',
    method: 'post',
    response() {
      return {
        errno: 0,
        data: {
          id: Random.id(),
        },
      }
    },
  },
]
export default userMock

原文链接:https://juejin.cn/post/7219189313723793465 作者:shibin