五:以理论结合实践方式梳理前端 React 框架 ——— 脚手架项目

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.jsondependencies 配置如下:

{
    ......
    "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.lessApp.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 主题色需要引用 cracocraco-less 两个插件,基于 less-loadermodifyVars 来进行主题配置,变量和其他配置方式可以参考如下:

@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.jsonscripts 脚本启动配置,如下:

"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). 渲染图表

  1. 引入:import { Chart } from ‘@antv/g2’;

  2. 接口返回数据后创建对象,const chart = new Chart({container: ‘ID’});

  3. 载入数据:chart.data(data); {里面data是接口返回数据};

  4. 创建图形语法:chart.interval().position(‘genre*sold’);

  5. 渲染图表: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')
);

545

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						# 项目的路由配置

分别在 IndexPageInvalPageLoginPage 下创建对应的 index.jsindex.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>&nbsp;&nbsp;
				<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-domuseHistory

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>&nbsp;&nbsp;
				<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>&nbsp;&nbsp;
        	<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-domRedirect 对象进行路由重定向

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 的属性 exactstrict 精准匹配路由,同时使用 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>&nbsp;&nbsp;
			<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>&nbsp;&nbsp;
			<Link to="/login">Login 页面</Link>&nbsp;&nbsp;
			<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>&nbsp;&nbsp;
			<Link to="/login">Login 页面</Link>&nbsp;&nbsp;
			<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>&nbsp;&nbsp;
			<Link to="/login">Login 页面</Link>&nbsp;&nbsp;
			<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>&nbsp;&nbsp;
			<Link to="/login">Login 页面</Link>&nbsp;&nbsp;
			<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
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值