React 04 :: Routing

296 阅读2分钟

前言

本篇文章简单谈一谈如何使用react-router-dom实现在不同的Component之间进行routing。

本文的Demo地址:

gitlab.com/yafeya/reac…

1. 安装react-router-dom

npm install react-router-dom
npm install @types/react-router-dom --save-dev

2. 目标

我的目标是基于上一次做的Demo,添加两个ComponentHomeRedux,然后能够在这两个component之间进行routing

Home用于显示最开始Demo中的那段文字和超链接。

Redux用于显示Redux Demo中的ClockComponentLikeComponent

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, LinkButton

Link用来RoutingRedux

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一样,这里也添加了LinkButton两个widget, 用于routingHomeComponent和执行后退操作。

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. 运行效果

screen-capture (1).gif

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就可以返回我们需要的效果了。

screen-capture (3).gif