react 项目搭建
通过 node 本地服务端进行前端项目的搭建,这样的操作,除了工程化管理项目,还可以整合团队成员开发,分发开发,提高开发效率。本文不对 node 进行细讲,能够有所了解并会基本的使用即可,至于 node 的安装,建议参考【开发工具 —— 前端工程开发环境 Node 之 NVM 管理应用】此片文章。
回归主体,本章主题讲解如何使用 node 环境使用 react 脚手架创建项目,并引入 react 全家桶以及配套的 ant design 的 UI 引用。
$ npx create-react-app react-demo
$ cd react-demo
$ npm start
进入 cmd,切换到您习惯存放代码的磁盘(以 window 为例:F:\
>)在执行项目创建之前,首先切换淘宝镜像源,为了加快项目安装依赖速度
$ npm config set registry https://registry.npm.taobao.org
$ npm config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/
$ npm config get registry
$ npm config get sass_binary_site
PS:后面两个是用于查看是否设置成功,当然,也可以到 C:\Users\fore8
下查看是否存在 .npmrc
文件
执行 npx create-react-app react-demo
回车后会在 F 盘下面创建 react-demo 项目,并进行相关依赖的安装,依赖安装完毕后,切换到项目并运行项目查看
当你看到运行如下效果,则表示项目运行成功啦,浏览器自动运行:http://localhost:3000 就可以打开 react-demo
$ Compiled successfully!
$
$ You can now view react-demo in the browser.
$
$ Local: http://localhost:3000
$ On Your Network: http://192.168.146.1:3000
$
$ Note that the development build is not optimized.
$ To create a production build, use npm run build.
注:这里需要你安装好 NodeJs 版本最好选择目前比较文档新版本,且支持 npx 即可
react 结构解析
|-- react-demo
|-- node_modules react 项目所需要的相关依赖包
|-- public react 项目入口资源文件
|-- src react 项目入口源码文件
|-- .eslintcache react 语法规则配置缓存
|-- .gitignore git 忽略文件配置项
|-- package-lock.json react 所有依赖指引锁定配置
|-- package.json react 所有依赖指引配置
|-- README.md react 项目文档
通过编辑器(推荐 VS Code)打开项目,先调整项目 src 目录内容,删除 App.css、index.css、App.js、App.test.js、logo.svg、reportWebVitals.js、setupTests.js,并改造 index.js 内代码如下:
import React from 'react';
import ReactDOM from 'react-dom';
ReactDOM.render(
<h1>Hello React!</h1>,
document.getElementById('root')
);
由于 create-react-app
创建的react应用是将webpack的配置项隐藏的,可以让开发者在不需要做任何配置的情况下开发react,但有时候开发者也会需要有些特殊的需求,
修改端口号
1)通过 cross-env
插件来修改服务启动端口号
$ npm install cross-env --save
# 找到 package.json 内的 script 部分改成如下:
"start": "cross-env PORT=5000 node scripts/start.js"
2)通过 webpack
配置来修改服务启动端口号
create-react-app
默认是将 webpack
配置隐藏啦,需要通过 npm run eject
命令将所有内建的配置暴露出来
$ npm run eject
> react-demo@0.1.0 eject E:\wwwroot\react-demo
> react-scripts eject
NOTE: Create React App 2+ supports TypeScript, Sass, CSS Modules and more without ejecting: https://reactjs.org/blog/2018/10/01/create-react-app-v2.html
? Are you sure you want to eject? This action is permanent. » (y/N)
选择 y (yes) 继续,如果报出 npm 关联错误,记得到项目的根目录,删除项目中的 .git 隐藏文件夹,配置暴露后的项目结构:
|-- react-demo
|-- config react 项目 webpack 相关配置文件
|-- node_modules react 项目所需要的相关依赖包
|-- public react 项目入口资源文件
|-- scripts react 项目启动脚本文件
|-- src react 项目入口源码文件
|-- .eslintcache react 语法规则配置缓存
|-- .gitignore git 忽略文件配置项
|-- package-lock.json react 所有依赖指引锁定配置
|-- package.json react 所有依赖指引配置
|-- README.md react 项目文档
找到项目下的 /scripts/start.js 文件,找到 const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000; 【48 Line】并进行求改,重新启动
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 6000;
附加:由于 create-react-app
创建的项目有自己独立的一套代码 eslint
配置,此时查看每个文件都爆红,这里打开 package.json
找到 eslintConfig
将其引用删除即可
修改依赖分配
另外系统默认将所有的依赖都分配到 dependencies
生产环境下,像 webpack
这类的插件一般使用在开发中,所有将项目的依赖分配一下,重新安装一下即可,基于当前调整安装如下:
> npm install @babel/core --save-dev
> npm install @pmmmwh/react-refresh-webpack-plugin --save-dev
> npm install @svgr/webpack --save-dev
> npm install babel-loader --save-dev
> npm install babel-preset-react-app --save-dev
> npm install case-sensitive-paths-webpack-plugin --save-dev
> npm install css-loader --save-dev
> npm install css-minimizer-webpack-plugin --save-dev
> npm install eslint --save-dev
> npm install eslint-config-react-app --save-dev
> npm install eslint-webpack-plugin --save-dev
> npm install file-loader --save-dev
> npm install fs-extra --save-dev
> npm install html-webpack-plugin --save-dev
> npm install mini-css-extract-plugin --save-dev
> npm install postcss --save-dev
> npm install postcss-flexbugs-fixes --save-dev
> npm install postcss-loader --save-dev
> npm install postcss-normalize --save-dev
> npm install postcss-preset-env --save-dev
> npm install resolve --save-dev
> npm install resolve-url-loader --save-dev
> npm install sass-loader --save-dev
> npm install style-loader --save-dev
> npm install terser-webpack-plugin --save-dev
> npm install webpack --save-dev
> npm install webpack-dev-server --save-dev
# 清理一些不常用的插件,完全是选择性的
> npm uninstall sass-loader --save # 使用 less 语法糖
> npm uninstall prompts --save # 用户交互提示
> npm uninstall source-map-loader --save # 提示映射文件,还需要清理 webpack.config.js
> npm uninstall tailwindcss --save # 一套 CSS 样式表,还需要清理 webpack.config.js
> npm uninstall identity-obj-proxy --save # 使用 ES6 代理的身份对象,还需要清理 package.json
> npm uninstall workbox-webpack-plugin --save # 需要清理 webpack.config.js
package.json
的 dependencies
配置如下:
{
......
"dependencies": {
"@testing-library/jest-dom": "^5.16.2",
"@testing-library/react": "^12.1.4",
"@testing-library/user-event": "^13.5.0",
"babel-jest": "^27.4.2",
"babel-plugin-named-asset-import": "^0.3.8",
"bfj": "^7.0.2",
"browserslist": "^4.18.1",
"camelcase": "^6.3.0",
"dotenv": "^10.0.0",
"dotenv-expand": "^5.1.0",
"jest": "^27.4.3",
"jest-resolve": "^27.4.2",
"jest-watch-typeahead": "^1.0.0"
"react": "^17.0.2",
"react-app-polyfill": "^3.0.0",
"react-dev-utils": "^12.0.0",
"react-dom": "^17.0.2",
"react-refresh": "^0.11.0",
"semver": "^7.3.5",
"web-vitals": "^2.1.4"
},
......
}
其中如下几个是用以测试相关插件:
"@testing-library/jest-dom": "^5.16.2",
"@testing-library/react": "^12.1.4",
"@testing-library/user-event": "^13.5.0",
"babel-jest": "^27.4.2",
"jest": "^27.4.3",
"jest-resolve": "^27.4.2",
"jest-watch-typeahead": "^1.0.0"
引用 LESS 语法糖
> npm install less less-loader --save-dev
找到 webpack.config.js
中的 const sassRegex
【大约 72行】,进行修改,使用处相应做调整
> ......
> const cssRegex = /\.css$/;
> const cssModuleRegex = /\.module\.css$/;
- const sassRegex = /\.(scss|sass)$/;
+ const lessRegex = /\.less$/;
- const sassModuleRegex = /\.module\.(scss|sass)$/;
+ const lessModuleRegex = /\.module\.less$/;
> ......
> {
- test: sassRegex,
+ test: lessRegex,
- exclude: sassModuleRegex,
+ exclude: lessModuleRegex,
> use: getStyleLoaders(
> ...
- 'sass-loader'
+ 'less-loader'
> ),
> sideEffects: true,
> },
> {
- test: sassModuleRegex,
+ test: lessModuleRegex,
> use: getStyleLoaders(
> ...
- 'sass-loader'
+ 'less-loader'
> ),
> },
> ......
将 index.css
改为 index.less
和 App.css
改为 App.less
,然后运行项目即可
react 按需加载
antd
是基于 Ant Design 设计体系的 React UI 组件库,主要用于研发企业级中后台产品。
antd
特性:
- 提炼自企业级中后台产品的交互语言和视觉风格。
- 开箱即用的高质量 react 组件。
- 使用 typescript 开发,提供完整的类型定义文件。
- 全链路开发和设计工具体系。
- 数十个国际化语言支持。
- 深入每个细节的主题定制能力。
antd
为 Web 应用提供了丰富的基础 UI 组件,如果直接引入使用,就会多出许多未用到的组件代码,就是明明只操作 DOM 查询,还非得引入一个 jquery 插件,为了压缩前端 UI 组件代码,需要按需引入加载所引用的 UI 组件代码
PS:如果 antd
采用的是 V3 版本的话就需要安装 babel-plugin-import
插件,用于 antd 的按需加载
$ npm install antd@3.x --save
$ npm install babel-plugin-import --save-dev
安装完babel-plugin-import
后,修改根目录下的package.json babel处,在persets后面添加,在 index.js 代码中引入代码如下
{
......
"babel": {
"presets": [
"react-app"
],
"plugins": [
[
"import",
{
"libraryName": "antd",
"libraryDirectory": "es",
"style": "css"
}
]
]
},
......
}
import React from 'react';
import ReactDOM from 'react-dom';
import { Button } from 'antd';
ReactDOM.render(
<div>
<Button type="primary">Primary Button</Button>
<Button>Default Button</Button>
<Button type="dashed">Dashed Button</Button>
<br />
<Button type="text">Text Button</Button>
<Button type="link">Link Button</Button>
</div>,
document.getElementById('root')
);
antd
从 V4+ 版本就默认是按需加载的,仅仅在 App.js 文件内直接引入 @import '~antd/dist/antd.css';
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.css';
import { Button } from 'antd';
ReactDOM.render(
<div>
<Button type="primary">Primary Button</Button>
<Button>Default Button</Button>
<Button type="dashed">Dashed Button</Button>
<br />
<Button type="text">Text Button</Button>
<Button type="link">Link Button</Button>
</div>,
document.getElementById('root')
);
运行后的效果如下图示:
引用 LESS 语法糖
import React from 'react';
import ReactDOM from 'react-dom';
import 'antd/dist/antd.less';
import { Button } from 'antd';
ReactDOM.render(
<div>
<Button type="primary">Primary Button</Button>
<Button>Default Button</Button>
<Button type="dashed">Dashed Button</Button>
<br />
<Button type="text">Text Button</Button>
<Button type="link">Link Button</Button>
</div>,
document.getElementById('root')
);
调整主题色
根据文档说明,用户自定义 antd
主题色需要引用 craco
和 craco-less
两个插件,基于 less-loader
的 modifyVars
来进行主题配置,变量和其他配置方式可以参考如下:
@primary-color: #1890ff; // 全局主色
@link-color: #1890ff; // 链接色
@success-color: #52c41a; // 成功色
@warning-color: #faad14; // 警告色
@error-color: #f5222d; // 错误色
@font-size-base: 14px; // 主字号
@heading-color: rgba(0, 0, 0, 0.85); // 标题色
@text-color: rgba(0, 0, 0, 0.65); // 主文本色
@text-color-secondary: rgba(0, 0, 0, 0.45); // 次文本色
@disabled-color: rgba(0, 0, 0, 0.25); // 失效色
@border-radius-base: 2px; // 组件/浮层圆角
@border-color-base: #d9d9d9; // 边框色
@box-shadow-base: 0 3px 6px -4px rgba(0, 0, 0, 0.12), 0 6px 16px 0 rgba(0, 0, 0, 0.08), 0 9px 28px 8px rgba(0, 0, 0, 0.05); // 浮层阴影
首先需要安装关联插件,然后在项目的根路径下创建一个 craco.config.js
配置文件,配置文件信息如下:
> npm install @craco/craco --save-dev
> npm install craco-less --save-dev
const CracoLessPlugin = require('craco-less');
module.exports = {
plugins: [
{
plugin: CracoLessPlugin,
options: {
lessLoaderOptions: {
lessOptions: {
modifyVars: {
'@primary-color': '#ff0000',
// 需要重置那个颜色,就根据上面的文档参考进行 LESS 变量赋值
},
javascriptEnabled: true,
},
},
},
},
],
};
至此,还需要调整项目的启动方式,调整为启动自定义配置方式,修改 package.json
的 scripts
脚本启动配置,如下:
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test"
},
react 图表引用
G2 是一套基于图形语法理论的可视化底层引擎,以数据驱动,提供图形语法与交互语法,具有高度的易用性和扩展性。使用 G2,你可以无需关注图表各种繁琐的实现细节,一条语句即可使用 Canvas 或 SVG 构建出各种各样的可交互的统计图表
G2 特性:
- 完善的图形语法:数据到图形的映射,能够绘制出所有的图表;
- 全新的交互语法:通过触发和反馈机制可以组合出各种交互行为,对数据进行探索;
- 强大的 View 模块:可支持开发个性化的数据多维分析图形;
- 双引擎渲染:Canvas 或 SVG 任意切换;
- 可视化组件体系:面向交互、体验优雅;
- 全面拥抱 TypeScript:提供完整的类型定义文件
$ npm install --save-dev @antv/g2
使用:1). 创建对象,2). 载入数据,3). 创建语法,4). 渲染图表
-
引入:import { Chart } from ‘@antv/g2’;
-
接口返回数据后创建对象,const chart = new Chart({container: ‘ID’});
-
载入数据:chart.data(data); {里面data是接口返回数据};
-
创建图形语法:chart.interval().position(‘genre*sold’);
-
渲染图表:chart.render()
import React, { useEffect } from 'react';
import ReactDOM from 'react-dom';
import { Chart } from '@antv/g2';
function App () {
useEffect(() => {
const data = [
{ genre: 'Sports', sold: 275 },
{ genre: 'Strategy', sold: 115 },
{ genre: 'Action', sold: 120 },
{ genre: 'Shooter', sold: 350 },
{ genre: 'Other', sold: 150 },
];
// Step 1: 创建 Chart 对象
const chart = new Chart({
container: 'c1', // 指定图表容器 ID
width: 600, // 指定图表宽度
height: 300, // 指定图表高度
});
// Step 2: 载入数据源
chart.data(data);
// Step 3: 创建图形语法,绘制柱状图
chart.interval().position('genre*sold');
// Step 4: 渲染图表
chart.render();
});
return <div id="c1"></div>
}
ReactDOM.render(
<App />,
document.getElementById('root')
);
react 路由配置
通常 react 开发的是一个基于 SPA 单页面的 web 应用,实现页面局部刷新,由一个路由映射一个映射组件,类似于 key(路径)— value(组件),通过切换组件及修饰路由地址的方式,实现页面的伪跳转
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<script src="https://cdn.bootcdn.net/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<script src="https://cdn.bootcdn.net/ajax/libs/babel-standalone/7.0.0-beta.3/babel.min.js"></script>
</head>
<body>
<div id="main"></div>
<script type="text/babel">
function LoginComponent (props) {
return <h1>登录页面</h1>
}
function HomeComponent (props) {
return <h1>首页页面</h1>
}
class App extends React.Component {
render() {
const flag = 0;
return (
<div>
{
flag ? <HomeComponent /> : <LoginComponent />
}
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('main'))
</script>
</body>
</html>
按道理只要改变 flag 的值就能改变 App 组件内的子组件,从而渲染不同的页面,实现页面的跳转
react 是通过 react-router-dom
进行路由的管理
> npm install react-router-dom --save
调整项目的 src
项目目录分配,如下:
|-- src
|-- assets # 存放项目相关静态资源,如:图片
|-- components # 存放项目通用组件
|-- mock # 暴露出项目所需的模拟数据
|-- pages # 项目的主页面:布局、404、登陆
|-- IndexPage # 项目的布局页面,通常引用 antd 的布局组件
|-- InvalPage # 项目的意外页面,不匹配相关路由的展示页
|-- LoginPage # 项目的登陆页面,有些项目登陆放在布局头部
|-- panes # 存放项目布局用到的版面组件
|-- redux # 项目的状态管理目录
|-- utils # 项目的工具集
|-- index.js # 项目的注册入口
|-- index.less # 项目的全局样式
|-- reportWebVitals.js # 旨在提供各种质量信号的统一指南
|-- root.js # 项目的路由根文件
|-- route.js # 项目的路由配置
分别在 IndexPage
、InvalPage
和 LoginPage
下创建对应的 index.js
和 index.less
文件,编辑内容如下:
import React from 'react';
import './index.less';
function IndexPage() {
return (<div>布局组件</div>)
}
export default IndexPage
import React from 'react';
import './index.less';
function InvalPage() {
return (<div>404组件</div>)
}
export default InvalPage
import React from 'react';
import './index.less';
function LoginPage() {
return (<div>登录组件</div>)
}
export default LoginPage
编辑 root.js
路由根文件,引入相关页面,基于 react-router-dom
路由对象进行路由配置
import React from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import IndexPage from './pages/IndexPage';
import InvalPage from './pages/InvalPage';
import LoginPage from './pages/LoginPage';
function Root() {
return (
<Router>
<Route path="/" component={IndexPage} />
<Route path="/login" component={LoginPage} />
</Router>
);
}
export default Root;
这个时候,可以通过 http://localhost:3000/ 和 http://localhost:3000/login 分别访问到首页和登录页面啦
import React from 'react';
import { HashRouter as Router, Route } from 'react-router-dom'; // Hash 路由:地址会自动添加 /#
import IndexPage from './pages/IndexPage';
import InvalPage from './pages/InvalPage';
import LoginPage from './pages/LoginPage';
function Root() {
return (
<Router>
<Route path="/" component={IndexPage} />
<Route path="/login" component={LoginPage} />
</Router>
);
}
export default Root;
可以通过 http://localhost:3000/#/ 和 http://localhost:3000/#/ 分别访问到首页和登录页面啦
HashRouter 相当于锚点定位,因此不论#后面的路径怎么变化,请求的都相当于是 # 之前的那个页面。而 BrowserRouter 模式下请求的链接相当于每个 URL 都会访问一个不同的后端地址,如果后端没有覆盖到路由就会产生404错误。如果确定使用 BrowserRouter 模式,需要进行前后端分离部署,使用 Nginx 反向代理服务器进行请求分发
import React from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import IndexPage from './pages/IndexPage';
import InvalPage from './pages/InvalPage';
import LoginPage from './pages/LoginPage';
function Root() {
return (
<Router>
<div>
<Link to="/">Home 页面</Link>
<Link to="/login">Login 页面</Link>
</div>
<Route path="/" component={IndexPage} />
<Route path="/login" component={LoginPage} />
</Router>
);
}
export default Root;
通过 Link 配置锚点链接,实现 SPA 单页面应用的页面跳转效果,除了通过 Link 配置锚点链接,还可以通过 props.history 对象做路由指向跳转,push 是覆盖,历史记录存在,replace 是替换当前路由,点击按钮执行页面跳转,需要 react-router-dom
的 useHistory
import React from 'react';
import { BrowserRouter as Router, Route, Link, useHistory } from 'react-router-dom';
import IndexPage from './pages/IndexPage';
import InvalPage from './pages/InvalPage';
import LoginPage from './pages/LoginPage';
function Root() {
const history = useHistory(); // useHistory() 是一个钩子函数
const handHome = () => history.push('/');
const handLogn = () => history.push('/login');
return (
<Router>
<div>
<button onClick={handHome}>Home 页面</button>
<button onClick={handLogn}>Login 页面</button>
</div>
<Route path="/" component={IndexPage} />
<Route path="/login" component={LoginPage} />
</Router>
);
}
export default Root;
react-router-dom
从 V5+ 开始使用 useHistory()
钩子函数来获得 history
对象,而 V4 一下版本需要 withRouter
高阶组件
import React from 'react';
import { withRouter } from 'react-router-dom';
function HeadComponent(props) {
const handHome = () => props.history.push('/');
const handLogn = () => props.history.push('/login');
return (
<div>
<button onClick={handHome}>Home 页面</button>
<button onClick={handLogn}>Login 页面</button>
</div>
);
}
export default withRouter(HeadComponent);
import React from 'react';
import { BrowserRouter as Router, Route } from 'react-router-dom';
import HeadComponent from './components/HeadComponent';
import IndexPage from './pages/IndexPage';
import InvalPage from './pages/InvalPage';
import LoginPage from './pages/LoginPage';
function Root() {
return (
<Router>
<HeadComponent />
<Route path="/" component={IndexPage} />
<Route path="/login" component={LoginPage} />
</Router>
);
}
export default Root;
通常要进入首页,就必须要登陆,一般默认访问 http://localhost:3000/,通过 react-router-dom
的 Redirect
对象进行路由重定向
import React from 'react';
import { Redirect } from 'react-router-dom';
import './index.less';
function IndexPage() {
const token = '';
if (token.length === 0) return <Redirect to='/login' />
return (<div>布局组件</div>)
}
export default IndexPage
配置 Route
的属性 exact
及 strict
精准匹配路由,同时使用 Switch
确保路由匹配具有唯一项,注意 404 页面必须要放在最后一项
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import HeadComponent from './components/HeadComponent';
import IndexPage from './pages/IndexPage';
import InvalPage from './pages/InvalPage';
import LoginPage from './pages/LoginPage';
function Root() {
return (
<Router>
<HeadComponent />
<Switch>
<Route exact strict path="/" component={IndexPage} />
<Route exact strict path="/login" component={LoginPage} />
<Route component={InvalPage} />
</Switch>
</Router>
);
}
export default Root;
大部分网站头部导航组件通常被选中的时候会有个 active
样式状态,react-router-dom
提供的 NavLink
对象,会给超链接添加一个选中状态 active 的类名,从而可以给导航链接选中加个样式,也可以通过 activeClassName 自定义选中类名
import React from 'react';
import { withRouter, NavLink } from 'react-router-dom';
function HeadComponent(props) {
return (
<div>
<NavLink to="/">Home 页面</NavLink>
<NavLink to="/login">Login 页面</NavLink>
</div>
);
}
export default withRouter(HeadComponent);
Route
对象除了直接匹配 component
组件,还可以基于 render
属性再次封装组件,这样可以将参数作为属性方式传递
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import HeadComponent from './components/HeadComponent';
import IndexPage from './pages/IndexPage';
import InvalPage from './pages/InvalPage';
import LoginPage from './pages/LoginPage';
function Root() {
return (
<Router>
<HeadComponent />
<Switch>
<Route exact strict path="/" component={IndexPage} />
<Route exact strict path="/login" render={(props) => <LoginPage {...props} name='名称' />} />
<Route component={InvalPage} />
</Switch>
</Router>
);
}
export default Root;
react 路由传参
1)以 /:[arg-name]?
方式进行 URL 参数传值,? 表示参数可有可无,通过 props.match.params
对象得到 URL 传递的参数
import React from 'react';
import { withRouter, Link } from 'react-router-dom';
function HeadComponent(props) {
return (
<div>
<Link to="/">Home 页面</Link>
<Link to="/login">Login 页面</Link>
<Link to="/mine/12/tom">Login 页面</Link>
</div>
);
}
export default withRouter(HeadComponent);
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import HeadComponent from './components/HeadComponent';
import IndexPage from './pages/IndexPage';
import InvalPage from './pages/InvalPage';
import LoginPage from './pages/LoginPage';
import UminePage from './pages/UminePage';
function Root() {
return (
<Router>
<HeadComponent />
<Switch>
<Route exact strict path="/" component={IndexPage} />
<Route exact strict path="/login" component={LoginPage} />
<Route exact strict path="/mine/:id/:name?" component={UminePage} />
<Route component={InvalPage} />
</Switch>
</Router>
);
}
export default Root;
import React from 'react';
import './index.less';
function UminePage(props) {
const { id, name } = props.match.params;
console.log(id, name);
return (<div>用户组件</div>)
}
export default UminePage
2)以 url?&
方式 URL 参数传值,通过 URLSearchParams
读取 URL 地址的参数数据,不推荐,容易将数据暴露出去
import React from 'react';
import { withRouter, Link } from 'react-router-dom';
function HeadComponent(props) {
return (
<div>
<Link to="/">Home 页面</Link>
<Link to="/login">Login 页面</Link>
<Link to="/mine?name=zhangsan&age=12">Login 页面</Link>
</div>
);
}
export default withRouter(HeadComponent);
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import HeadComponent from './components/HeadComponent';
import IndexPage from './pages/IndexPage';
import InvalPage from './pages/InvalPage';
import LoginPage from './pages/LoginPage';
import UminePage from './pages/UminePage';
function Root() {
return (
<Router>
<HeadComponent />
<Switch>
<Route exact strict path="/" component={IndexPage} />
<Route exact strict path="/login" component={LoginPage} />
<Route exact strict path="/mine/:id?/:name?" component={UminePage} />
<Route component={InvalPage} />
</Switch>
</Router>
);
}
export default Root;
import React from 'react';
import './index.less';
function UminePage(props) {
const params = new URLSearchParams(props.location.search);
console.log(params.get('name'), params.get('age'));
return (<div>用户组件</div>)
}
export default UminePage
url?&
也可以通过 query
方式进行 URL 参数传值,并且通过 querystring
来获取 URL 参数
import React from 'react';
import { withRouter, Link } from 'react-router-dom';
function HeadComponent(props) {
return (
<div>
<Link to="/">Home 页面</Link>
<Link to="/login">Login 页面</Link>
<Link to={{ pathname: '/mine', query: { name: 'zhangsan', age: 12 } }}>Login 页面</Link>
</div>
);
}
export default withRouter(HeadComponent);
import React from 'react';
import './index.less';
function UminePage(props) {
const params = querystring.parse(props.location.search.replace('?', ''));
console.log(params.name, params.age);
return (<div>用户组件</div>)
}
export default UminePage
3)以 state
状态形式进行数据传值,通过 state
状态获取传值参数
import React from 'react';
import { withRouter, Link } from 'react-router-dom';
function HeadComponent(props) {
return (
<div>
<Link to="/">Home 页面</Link>
<Link to="/login">Login 页面</Link>
<Link to={{ pathname: '/mine', state: { name: 'zhangsan', age: 12 } }}>Login 页面</Link>
</div>
);
}
export default withRouter(HeadComponent);
import React from 'react';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import HeadComponent from './components/HeadComponent';
import IndexPage from './pages/IndexPage';
import InvalPage from './pages/InvalPage';
import LoginPage from './pages/LoginPage';
import UminePage from './pages/UminePage';
function Root() {
return (
<Router>
<HeadComponent />
<Switch>
<Route exact strict path="/" component={IndexPage} />
<Route exact strict path="/login" component={LoginPage} />
<Route exact strict path="/mine/:id?/:name?" component={UminePage} />
<Route component={InvalPage} />
</Switch>
</Router>
);
}
export default Root;
import React from 'react';
import './index.less';
function UminePage(props) {
const params = this.props.location.state;
console.log(params.name, params.age);
return (<div>用户组件</div>)
}
export default UminePage