前言
本篇文章简单谈一谈如何使用react-router-dom实现在不同的Component之间进行routing。
本文的Demo地址:
1. 安装react-router-dom
npm install react-router-dom
npm install @types/react-router-dom --save-dev
2. 目标
我的目标是基于上一次做的Demo,添加两个Component,Home与Redux,然后能够在这两个component之间进行routing。
Home用于显示最开始Demo中的那段文字和超链接。
Redux用于显示Redux Demo中的ClockComponent和LikeComponent。
3. 添加HomeComponent
import { RouteComponentProps, Link } from "react-router-dom";
import logo from './logo.svg';
import { Image } from "./Image";
import { Paragraph } from "./Paragraph";
import { HyperLink } from "./HyperLink";
interface HomeProps extends RouteComponentProps {
}
export const Home: React.FC<HomeProps> = (props) => {
return (
<div className="App">
<header className="App-header">
<Image src={logo} alt="logo"></Image>
<Paragraph part1="Edit" code="src/App.tsx" part2="and save to reload."></Paragraph>
<HyperLink href="https://reactjs.org" title="Learn React"></HyperLink>
<Link to="/redux">Redux Demo</Link>
<button className="btn btn-primary" onClick={props.history.goBack}>Back</button>
</header>
</div>
);
}
基本上就是把之前的Image, Paragraph, 与HyperLink抄了过来,然后主要的是添加了后面两个widget, Link与Button。
Link用来Routing到Redux。
Button用于执行后退操作。
4. 添加ReduxComponent
import { RouteComponentProps, Link } from "react-router-dom";
import logo from './logo.svg';
import { Image } from "./Image";
import { LikeWrapper } from "./Like";
import { ClockWrapper } from "./Clock";
interface ReduxProps extends RouteComponentProps {
}
export const Redux: React.FC<ReduxProps> = (props) => {
return (
<div className="App">
<header className="App-header">
<Image src={logo} alt="logo"></Image>
<LikeWrapper></LikeWrapper>
<ClockWrapper></ClockWrapper>
<Link to="/">Home</Link>
<button className="btn btn-primary" onClick={props.history.goBack}>Back</button>
</header>
</div>
);
}
与HomeComponent一样,这里也添加了Link与Button两个widget, 用于routing到HomeComponent和执行后退操作。
5. 添加RouterComponent
import { BrowserRouter, Redirect, Route, Switch } from "react-router-dom";
import { Home } from "./Home";
import { Redux } from "./Redux";
export const Router = ()=>{
return (
<BrowserRouter>
<Switch>
// http://localhost:3000 显示HomeComponent
<Route exact={true} path="/" component={Home}/>
// http://localhost:3000/redux 显示ReudxComponent
<Route path="/redux" component={Redux}/>
// 默认显示HomeComponent
<Route component={()=> <Redirect to="/"/>} />
</Switch>
</BrowserRouter>
);
}
6. 修改AppComponent
import React, { Component } from 'react';
import './App.scss';
import { Router } from './Router';
export class App extends Component {
render() {
return (
// 注意这里的Router是我们自己创建的RouterComponent
<Router/>
);
}
}
7. 运行效果
8. Routing by URL
运行效果是不错,但是有个问题,如果我访问http://localhost:3000/redux, 我的预期是能够访问到我的ReduxComponent,但是,却返回了404页面。
是因为,React与Angular和Vue一样都是SPA(Single Page Application)。其实应用程序只有一个页面,只是http://localhost:3000。
为了解决这个问题,我们需要对Webpack进行一些修改。但是问题又来了,如果只对Webpack进行一点点修改,就eject整个项目,有点大炮打蚊子的感觉。
所以我们需要使用react-app-rewired包来override我们需要的webpack的配置。
8.1 Override Webpack without eject
npm i react-app-rewired --save-dev
添加config-overrides.js, 并添加如下模板
// config-overrides.js
module.exports = {
webpack: function (config, env) {
return config;
},
jest: function (config) {
return config;
},
devServer: function (configFunction) {
return function (proxy, allowedHost) {
return config;
};
},
paths: function (paths, env) {
return paths;
},
}
修改package.json的script
// ...
"scripts": {
"start": "react-app-rewired start", // react-scripts -> react-app-rewired
"build": "react-app-rewired build", // react-scripts -> react-app-rewired
"test": "react-app-rewired test", // react-scripts -> react-app-rewired
"eject": "react-scripts eject"
},
// ...
8.2 设置 historyApiFallback=true
修改devServer部分,其他不需要修改
// config-overrides.js
module.exports = {
// webpack: function (config, env) {
// return config;
// },
// jest: function (config) {
// return config;
// },
devServer: function (configFunction) {
return function (proxy, allowedHost) {
const config = configFunction(proxy, allowedHost);
config.historyApiFallback = true;
return config;
};
},
// paths: function (paths, env) {
// return paths;
// },
}
这样,我们访问http://localhost:3000/redux就可以返回我们需要的效果了。