从Demo开始进入React世界

在这个Demo里,我们会用到这些:

  • React
  • React-Router
  • Jest

cra新建项目

首先,我们暂时不必直接使用webpack来自己搭建一个项目,因为这太过费时,我们的目的是先能写

yarn create react-app react-demo --template typescript
复制代码

image.png

你可以直接复制我上面的代码片段,去创建一个名为react-demo的react+ts项目。

如果你不太喜欢用yarn,你也可以使用npm作为你的包管理器,代码如下:

npx create-react-app react-demo --template typescript
复制代码

如果你的操作和我一致的话,你应该会得到以下目录结构

├── README.md
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── logo192.png
│   ├── logo512.png
│   ├── manifest.json
│   └── robots.txt
├── src
│   ├── App.css
│   ├── App.test.tsx
│   ├── App.tsx
│   ├── index.css
│   ├── index.tsx
│   ├── logo.svg
│   ├── react-app-env.d.ts
│   ├── reportWebVitals.ts
│   └── setupTests.ts
├── tsconfig.json
└── yarn.lock
复制代码

启动项目

运行以下命令

yarn start
复制代码

如果你的电脑恰好没有安装高版本的webpack或者babel-loader,那么应该是可以正常运行,并自动打开以下页面:

image.png

如果,很不巧,它报了如下这种错误:

image.png

我相信你聪明的你一定可以猜到该如何解决这个问题了~

对的,没错,就是去/User/<yourName>/node_moudles下将提示的那一个依赖删除即可

需要注意的是,往往不会是只删除一个就会奏效,提示其它的依赖出现这种问题,也可以尝试使用这种方法去解决


做一些小改动

至此,我们的项目的初始化已经完成了

在接下来的这一步骤里,我们将完成一个小需求,具体如下:

写一个layout,layout中有两个按钮,点击这这两个按钮可以切换路由

接下来,我们需要做以下几件事:

  • 简单的配置一下环境
  • 添加路由
  • 写一个最简单的layout

环境配置

为了使我们的代码更加地规整,我们可以使用eslint+pritter来规范我们的代码

我们需要安装以下依赖

yarn add prettier eslint-config-prettier eslint-plugin-prettier eslint-plugin-react @typescript-eslint/parser @typescript-eslint/eslint-plugin eslint -D
复制代码

image.png

然后,我们开始建立配置文件

.eslintrc.js
module.exports = {
    parser: '@typescript-eslint/parser',
    extends: [
      'prettier',
    ],
    parserOptions: {
      ecmaVersion: 2020,
      sourceType: 'module',
      ecmaFeatures: {
        jsx: true,
        },
    },
    settings: {
      react: {
        version: 'detect',
        },
    },
};

复制代码
.prettierrc
{
    "semi": false,
    "singleQuote": false,
    "arrowParens": "avoid",
    "trailingComma": "none"
}

复制代码

另外,我本人还对vscode和editor做了一个配置

.vscode/settings.json
{
  "editor.formatOnSave": true,
  "files.autoSave": "onWindowChange",
  "editor.codeActionsOnSave": {
    "source.fixAll": true
  }
}
复制代码
.editorconfig
root = true

[*]
indent_style = space
indent_size = 2
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
end_of_line = lf

[*.md]
trim_trailing_whitespace = false

复制代码
pre-commit钩子

同时,我还期望当我们提交代码的时候,eslint可以自动执行并修复一些我们可能没有看到的问题

我们需要先安装以下依赖

yarn add husky lint-staged -D
复制代码

image.png

然后我们需要在package.json里添加这样一段代码:

"lint-staged": {
    "*.+(ts|tsx|js|jsx)": [
      "eslint --fix",
      "git add"
    ],
    "*.+(json|css|md)": [
      "prettier --write",
      "git add"
    ]
  },
  "husky": {
    "hooks": {
      "pre-commit": "lint-staged"
    }
  }
复制代码

至此,最初始的环境已经配的差不多了,下面就可以开始正经写代码啦~
当然,随着后续代码的不断增加,我们肯定还是要做些更新的,不过这是以后的事了~

添加路由

在这里,我们会使用react-router5.x的版本

对应react-web端开发,我们需要安装 react-router-dom

同时,又因为我们使用的是typescript的缘故,所以,我们还需要安装 @types/react-router

执行以下操作:

yarn add react-router-dom
复制代码
yarn add @types/react-router -D
复制代码

在src目录下建三个文件夹 views route Layout

views

在views文件夹下

views/pageA/index.tsx

import React from "react"

export default function PageA() {
  return <div>this is pageA</div>
}

复制代码

views/pageB/index.tsx

import React from "react"

export default function PageA() {
  return <div>this is pageB</div>
}

复制代码

同时,在Layout下:
Layout/Layout.tsx

import * as React from "react"
import { Link } from "react-router-dom"

const Layout = () => {
  return (
    <div>
      <div>this is a layout Component</div>
    </div>
  )
}

export default Layout

复制代码

Layout/index.ts

export { default } from "./Layout"
复制代码
route

我们建立一个router.config.ts的文件,用于存放我们的路由表
route/router.config.ts

import Layout from "../Layout"
import { lazy } from "react"
const RouteConfig = [
  {
    path: "/pages",
    component: Layout,
    children: [
      {
        path: "/pages/page-a",
        component: lazy(() => import("../views/pageA"))
      },
      {
        path: "/pages/page-b",
        component: lazy(() => import("../views/pageB"))
      },
      { path: "/pages", redirect: "/pages/paeg-a" }
    ]
  },
  {
    path: "/",
    redirect: "/pages/page-a"
  }
]

export default RouteConfig
复制代码

然后,我们还需要建一个RouteView组件,用于渲染我们的路由

route/RouteView.tsx

import React from "react"
import { Redirect, Route, Switch } from "react-router-dom"

export interface IRouteViewProps {
  path?: string
  redirect?: string
  component?: any
  children?: IRouteViewProps[]
}

const RouteView: React.FC<IRouteViewProps> = props => {
  return (
    <Switch>
      {props.children &&
        props.children.map((item, index) => {
          if (item.redirect) {
            return (
              <Redirect
                key={index}
                from={item.path}
                to={item.redirect}
              ></Redirect>
            )
          }
          return (
            <Route
              key={index}
              path={item.path}
              render={(props: JSX.IntrinsicAttributes) => {
                return (
                  item.component && (
                    <item.component
                      children={item.children}
                      {...props}
                    ></item.component>
                  )
                )
              }}
            ></Route>
          )
        })}
    </Switch>
  )
}

export default RouteView

复制代码
App && Layout

然后我们改造一下我们src下的App.tsx

需要注意的是,我这里使用的是BrowserRouter

src/App.tsx

import React, { Suspense } from "react"

import { BrowserRouter } from "react-router-dom"

import RouteConfig from "./route/router.config"
import RouteView from "./route/RouteView"

import "./App.css"

function App() {
  return (
    <div className="App">
      <BrowserRouter>
        <Suspense fallback={<div>loading...</div>}>
          <RouteView children={RouteConfig}></RouteView>
        </Suspense>
      </BrowserRouter>
    </div>
  )
}

export default App

复制代码

相应的App.css我也做了一点更改

src/App.css

.App {
  text-align: center;
}

.App a {
  margin-left: 12px;
}

复制代码

最后,再让我们来改造一下我们的Layout

Layout/Layout.tsx

import * as React from "react"
import { Link } from "react-router-dom"
import { History } from "history"
import RouteView, { IRouteViewProps } from "../route/RouteView"

interface ILayoutProps extends IRouteViewProps {
  history: History
}

const Layout = (props: ILayoutProps) => {
  return (
    <div>
      <div>this is a layout Component</div>
      <Link to="/pages/page-a">page-A</Link>
      <Link to="/pages/page-b">page-B</Link>
      <RouteView {...props} />
    </div>
  )
}

export default Layout
复制代码

当前目录结构如下:

.
├── README.md
├── package.json
├── public
│   ├── favicon.ico
│   ├── index.html
│   ├── manifest.json
│   └── robots.txt
├── src
│   ├── App.css
│   ├── App.test.tsx
│   ├── App.tsx
│   ├── Layout
│   │   ├── Layout.tsx
│   │   └── index.ts
│   ├── index.css
│   ├── index.tsx
│   ├── logo.svg
│   ├── react-app-env.d.ts
│   ├── reportWebVitals.ts
│   ├── route
│   │   ├── RouteView.tsx
│   │   └── router.config.ts
│   ├── setupTests.ts
│   └── views
│       ├── pageA
│       │   └── index.tsx
│       └── pageB
│           └── index.tsx
├── tsconfig.json
└── yarn.lock
复制代码

运行代码

执行 yarn start 我们将看到如下效果:

QQ20210629-120221-HD.gif


2021.06.29,我们下周见~

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享