react-router

react-router 学习笔记

学习地址

https://github.com/ReactTraining/react-router

准备前工作

  1. 创建一个react项目
 npm install -g create-react-app yarn
  create-react-app antd-demo
   cd antd-demo
  $ yarn start
  1. 下载添加路由
npm i -D react-router react-router-dom

基本功

  1. 添加导航
            
  • Home
  • Topics
  1. 添加导航对应的组件
            
            
  1. 添加一级组件

// 设置Home组件
const Home = () => (
    

Home

); // 设置 Topics组件 const Topics = ({ match }) => (

Topics

  • Rendering with React
  • Props v. State
// 设置一个组件, // 设置默认组件

Please select a topic.

} />
);
  1. 添加一级组件内二级导航
 
  • Rendering with React
  • Props v. State
  1. 添加二级导航组件
 // 设置一个组件,
        
  1. 添加二级导航默认组件
        // 设置默认组件
         

Please select a topic.

} />
  1. 添加二级组件
// 设置二级组件
const Topic = ({ match }) => {
    console.log(match);
    return (
        

{match.url}

) };
  1. 完整示范
  • src/views/basic/index.js
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";

// 设置根路由
const BasicExample = () => (
    // 根路由标签
    
        
  • Home
  • Topics

{/*// 设置跳转的组件*/}
); // 设置Home组件 const Home = () => (

Home

); // 设置 Topics组件 const Topics = ({ match }) => (

Topics

  • Rendering with React
  • Props v. State
// 设置一个组件, // 设置默认组件

Please select a topic.

} />
); // 设置二级组件 const Topic = ({ match }) => { console.log(match); return (

{match.url}

) }; export default BasicExample;
  • src/App.js
import React, { Component } from 'react';
import './App.css';
import BasicExample from './views/basic/index.js';
class App extends Component {
  render() {
    return (
      
); } } export default App;
  1. redirect 与登录验证
  2. 导入包
import React from "react";
import {
    BrowserRouter as Router,
    Route,
    Link,
    Redirect,
    withRouter
} from "react-router-dom";
  1. 添加路由导航
 
  • Public Page
  • Protected Page
  • logout Page
  1. 添加路由组件
{/*// 定义导航对应组件*/}
            
            {/*// 未登录的*/}
            
            {/*// 登录后的*/}
            
            
  1. 定义路由组件
  • 验证组件
// 判断是否登录, 如果登录, 则显示传递进来的组件, 否则重定向到登录组件
const PrivateRoute = ({ component: Component, ...rest }) => (
    
            fakeAuth.isAuthenticated ? (
                
            ) : (
                
            )
        }
    />
);
  • Public组件
  • Protected 组件
const Public = () => 

Public

; const Protected = () =>

Protected

;
  • 退出组件
class Logout extends React.Component {
    constructor(props){
        super(props)
        this.state = {
            redirectToReferrer: fakeAuth.isAuthenticated
        }
    }
    // 退出
    logout = () => {
        fakeAuth.signout(() => {
            this.setState({ redirectToReferrer: false });
        });
    };
    render() {
        const { from } = this.props.location.state || { from: { pathname: "/" } };
        const { redirectToReferrer } = this.state;
        // 判断是否登录,
        if (!redirectToReferrer) {
            return ()
        }
        // 未登录则提示登录
        return (
            

You must log in to view the page at {from.pathname}

); } }
  • 登录组件
class Login extends React.Component {
    constructor(props){
        super(props)
        this.state = {
            redirectToReferrer: fakeAuth.isAuthenticated
        }
    }
    // 登录, 通过验证,
    login = () => {
        fakeAuth.authenticate(() => {
            this.setState({ redirectToReferrer: true });
        });
    };

    render() {
        const { from } = this.props.location.state || { from: { pathname: "/" } };
        const { redirectToReferrer } = this.state;
        // 判断是否登录,
        if (redirectToReferrer) {
            return ;
        }
        // 未登录则提示登录
        return (
            

You must log in to view the page at {from.pathname}

); } }
  1. 验证数据

// 验证函数, 登录登出
const fakeAuth = {
    isAuthenticated: false,
    authenticate(cb) {
        this.isAuthenticated = true;
        setTimeout(cb, 100); // fake async
    },
    signout(cb) {
        this.isAuthenticated = false;
        setTimeout(cb, 100);
    }
};

匹配当前路径

  1. 定义匹配Link组件
- children  返回当前路径, 会与当前route组件进行匹配, 如果匹配, 则返回当了路径match, 否则返回Null
/*
* 有时您需要渲染路径是否与位置匹配。在这些情况下,您可以使用儿童道具功能。它的工作方式与渲染完全相同,只是它会被调用,无论是否匹配。子渲染道具接收与组件和渲染方法相同的所有路径道具,除非路径无法匹配URL,否则匹配为空。这允许您根据路径是否匹配动态调整UI。如果路线匹配,我们在这里添加一个活动类
* */
const OldSchoolMenuLink = ({ label, to, activeOnlyWhenExact }) => (
     {
            return (
                
{match ? "> " : ""} {label}
) }} /> );
  1. 添加导航

            
  1. 添加导航对应组件

            
  1. 定义组件

const Home = () => (
    

Home

); const About = () => (

About

);
  1. 完整代码
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import './index.css'
const CustomLinkExample = () => (
    
        

); /* * 有时您需要渲染路径是否与位置匹配。在这些情况下,您可以使用儿童道具功能。它的工作方式与渲染完全相同,只是它会被调用,无论是否匹配。子渲染道具接收与组件和渲染方法相同的所有路径道具,除非路径无法匹配URL,否则匹配为空。这允许您根据路径是否匹配动态调整UI。如果路线匹配,我们在这里添加一个活动类 * */ const OldSchoolMenuLink = ({ label, to, activeOnlyWhenExact }) => ( { console.log(match) return (
{match ? "> " : ""} {label}
) }} /> ); const Home = () => (

Home

); const About = () => (

About

); export default CustomLinkExample;

路由配置基础

  1. 引入对应的库
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
  1. 添加路由配置
const routes = [
    {
        path: "/sandwiches",
        component: Sandwiches
    },
    {
        path: "/tacos",
        component: Tacos,
        routes: [
            {
                path: "/tacos/bus",
                component: Bus,
                routes: [
                    {
                        path: "/tacos/bus/bus2",
                        component: Bus2
                    },
                    {
                        path: "/tacos/bus/bus3",
                        component: Bus3
                    }
                    ]
            },
            {
                path: "/tacos/cart",
                component: Cart
            }
        ]
    }
];

  1. 添加一级导航
  • Tacos
  • Sandwiches
  1. 定义一个渲染当前路由配置的组件

传入一个route, 根据route配置绑定给Route, 并使用render渲染该组件, 其中 route.component 是 route配置中的component, 是Route.render渲染时返回的渲染标签

const RouteWithSubRoutes = route => (
    (
                // pass the sub-routes down to keep nesting
                
            )
        }
    />
);
  1. 定义一个循环渲染当前路由数组的组件
  • 该组件值渲染当前数组的一级数组
const renderRoutes = (routes) => {return (routes.map((route, i) => ))};
  1. 渲染路由
{renderRoutes(routes)}
  1. 定义一级组件
  • Sandwiches组件
const Sandwiches = () => 

Sandwiches

;
  • Tacos组件
const Tacos = ({ routes }) => (
    

Tacos

);
  1. 准备渲染二级组件, 在路由配置对象内, 只有tacos组件才有子组件, 因此修改tacos组件
  • 这里添加了 二级导航, 和渲染二级导航对应的组件
  • 这里的routes 是render={props =>() 这里的 routes={route.routes}
  • renderRoutes组件是上面定义的组件, 他会帮我们循环routes数组, 然后渲染出当前数组的一维数组的组件
const Tacos = ({ routes }) => (
    

Tacos

  • Bus
  • Cart
{renderRoutes(routes)}
);
  1. 定义二级组件
  • Bus
const Bus = () => 

Bus

;
  • Cart
const Cart = () => 

Cart

;

10 二级组件定义好, 从路由配置上, 可以看出, 还有三级组件, 因此修改二级组件, 而在这里, 只有Bus组件才有三级组件, 因此只需要修改Bus组件就好

  • Bus
    跟前面的 Tacos 组件一样, 这里添加了三级导航, 并渲染了三级组件
const Bus = ({routes}) => {
    return (
        

Bus constructor
  • /tacos/bus/bus2
  • /tacos/bus/bus3

{renderRoutes(routes)}
) };
  1. 定义三级组件
const Bus2 = () => 

Bus2

; const Bus3= () =>

Bus3

;
  1. 完整代码
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
// first our route components
const Sandwiches = () => 

Sandwiches

; const Tacos = ({ routes }) => (

Tacos

  • Bus
  • Cart
{renderRoutes(routes)}
); const renderRoutes = (routes) => {return (routes.map((route, i) => ))}; const Bus = ({routes}) => { console.log(routes) return (

Bus constructor
  • /tacos/bus/bus2
  • /tacos/bus/bus3

{renderRoutes(routes)}
) }; const Bus2 = () =>

Bus2

; const Bus3= () =>

Bus3

; const Cart = () =>

Cart

; //////////////////////////////////////////////////////////// // then our route config const routes = [ { path: "/sandwiches", component: Sandwiches }, { path: "/tacos", component: Tacos, routes: [ { path: "/tacos/bus", component: Bus, routes: [ { path: "/tacos/bus/bus2", component: Bus2 }, { path: "/tacos/bus/bus3", component: Bus3 } ] }, { path: "/tacos/cart", component: Cart } ] } ]; // wrap and use this everywhere instead, then when // sub routes are added to any route it'll work const RouteWithSubRoutes = route => ( { console.log(props) console.log(route) return ( // pass the sub-routes down to keep nesting ) }} /> ); const RouteConfigExample = () => (
  • Tacos
  • Sandwiches
{renderRoutes(routes)}
); export default RouteConfigExample;

升级路由配置

  1. 定义一个路由配置
const routes = [
    {
        path: "/login",
        name: 'Login',
        component: Login
    },
    {
        path: "/tacos",
        name: 'Tacos',
        component: Tacos,
        routes: [
            {
                path: "/tacos/bus",
                name: "/tacos/bus",
                component: Bus,
                routes: [
                    {
                        path: "/tacos/bus/bus2",
                        name: "/tacos/bus/bus2",
                        component: Bus2
                    },
                    {
                        path: "/tacos/bus/bus3",
                        name: "/tacos/bus/bus3",
                        component: Bus3
                    }
                    ]
            },
            {
                path: "/tacos/cart",
                name: "/tacos/Cart",
                component: Cart
            }
        ]
    }
];
  1. 定义一级导航
 
  • Tacos
  • login
  1. 定义一级组件
 {routes.map((route, i) => )}
  1. 封装渲染当前组件的组件
const RouteWithSubRoutes = route => (
    {
            return (
                
            )
        }}
    />
);
  1. 定义一级组件
  • Login 组件
  • Tacos 组件
const Login = () => 

login

; const Tacos = ({ routes }) => (

Tacos

);
  1. 根据路由配置, 因为要在 Tacos组件内, 渲染二级组件, 所以需要修改Tacos组件
const Tacos = ({ routes }) => (
    

Tacos

    {slideMenu(routes)}
{renderRoutes(routes)}
);
  1. 循环渲染Link组件 slideMenu
  • OldSchoolMenuLink是封装的一层Link, 主要用来匹配当前组件并修改当前选中组件的样式
const slideMenu = (routes) => Array.isArray(routes) && routes.map(item => (
        
  • {/*{item.name}*/} {Array.isArray(item.routes) && item.routes.length > 0 && (
      {slideMenu(item.routes)}
    )}
  • ) );
    1. 渲染当前路由数组组件
    const renderRoutes = (routes) => {return (routes.map((route, i) => ))};
    
    1. 定义二级组件
    const Bus= () => 

    Bus

    ; const Cart = () =>

    Cart

    ;
    1. 修改 Bus组件
    • renderRoutes 这里会渲染当前组件下面的子组件
    const Bus = ({routes}) => {
        return (
            

    Bus constructor

    {renderRoutes(routes)}
    ) };
    1. 定义三级组件
    const Bus3= () => 

    Bus3

    ; const Cart = () =>

    Cart

    ;
    1. 完整代码
    • js
    import React from "react";
    import { BrowserRouter as Router, Route, Link } from "react-router-dom";
    import './index.css'
    
    // Some folks find value in a centralized route config.
    // A route config is just data. React is great at mapping
    // data into components, and  is a component.
    
    ////////////////////////////////////////////////////////////
    // first our route components
    const Login = () => 

    login

    ; const Tacos = ({ routes }) => (

    Tacos

      {slideMenu(routes)}
    {renderRoutes(routes)}
    ); const slideMenu = (routes) => Array.isArray(routes) && routes.map(item => (
  • {/*{item.name}*/} {Array.isArray(item.routes) && item.routes.length > 0 && (
      {slideMenu(item.routes)}
    )}
  • ) ); const renderRoutes = (routes) => {return (routes.map((route, i) => ))}; const Bus = ({routes}) => { return (

    Bus constructor

    {renderRoutes(routes)}
    ) }; const Bus2 = () =>

    Bus2

    ; const Bus3= () =>

    Bus3

    ; const Cart = () =>

    Cart

    ; //////////////////////////////////////////////////////////// // then our route config const routes = [ { path: "/login", name: 'Login', component: Login }, { path: "/tacos", name: 'Tacos', component: Tacos, routes: [ { path: "/tacos/bus", name: "/tacos/bus", component: Bus, routes: [ { path: "/tacos/bus/bus2", name: "/tacos/bus/bus2", component: Bus2 }, { path: "/tacos/bus/bus3", name: "/tacos/bus/bus3", component: Bus3 } ] }, { path: "/tacos/cart", name: "/tacos/Cart", component: Cart } ] } ]; const OldSchoolMenuLink = ({ label, to, exact }) => ( { return ( {match ? "> " : ""} {label} ) }} /> ); // wrap and use this everywhere instead, then when // sub routes are added to any route it'll work const RouteWithSubRoutes = route => ( { console.log(props) console.log(route) return ( // pass the sub-routes down to keep nesting ) }} /> ); const RouteConfigExample = () => (
    • Tacos
    • login
    {routes.map((route, i) => )}
    ); export default RouteConfigExample;
    • css
    .slider{
        width: 200px;
        float: left;
    }
    .content {
        width: 100%;
        padding-left: 200px;
    }
    
    ul{
        list-style: none;
        padding: 0;
        margin: 0;
    }
    
    li {
        padding: 0;
        text-align: left;
    }
    ul>li>ul {
        padding-left: 20px;
    }
    

    你可能感兴趣的:(react-router)