在这个Demo里,我们会用到这些:
- React
- React-Router
- Jest
cra新建项目
首先,我们暂时不必直接使用webpack来自己搭建一个项目,因为这太过费时,我们的目的是先能写
yarn create react-app react-demo --template typescript
复制代码
你可以直接复制我上面的代码片段,去创建一个名为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,那么应该是可以正常运行,并自动打开以下页面:
如果,很不巧,它报了如下这种错误:
我相信你聪明的你一定可以猜到该如何解决这个问题了~
对的,没错,就是去/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
复制代码
然后,我们开始建立配置文件
.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
复制代码
然后我们需要在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
我们将看到如下效果:
2021.06.29,我们下周见~