美文网首页
react-router

react-router

作者: Biao_349d | 来源:发表于2018-09-27 18:08 被阅读0次

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. 添加导航
            <ul>
                <li>
                    <Link to="/">Home</Link>
                </li>
                <li>
                    <Link to="/topics">Topics</Link>
                </li>
            </ul>
  1. 添加导航对应的组件
            <Route exact path="/" component={Home} />
            <Route path="/topics" component={Topics} />
  1. 添加一级组件

// 设置Home组件
const Home = () => (
    <div>
        <h2>Home</h2>
    </div>
);
// 设置 Topics组件
const Topics = ({ match }) => (
    <div>
        <h2>Topics</h2>
        <ul>
            <li>
                <Link to={`${match.url}/rendering`}>Rendering with React</Link>
            </li>
            <li>
                <Link to={`${match.url}/props-v-state`}>Props v. State</Link>
            </li>
        </ul>
        // 设置一个组件,
        <Route path={`${match.url}/:topicId`} component={Topic} />
        // 设置默认组件
        <Route
            exact
            path={match.url}
            render={() => <h3>Please select a topic.</h3>}
        />
    </div>
);
  1. 添加一级组件内二级导航
 <ul>
            <li>
                <Link to={`${match.url}/rendering`}>Rendering with React</Link>
            </li>
            <li>
                <Link to={`${match.url}/props-v-state`}>Props v. State</Link>
            </li>
        </ul>
  1. 添加二级导航组件
 // 设置一个组件,
        <Route path={`${match.url}/:topicId`} component={Topic} />
  1. 添加二级导航默认组件
        // 设置默认组件
        <Route
            exact
            path={match.url}
            render={() => <h3>Please select a topic.</h3>}
        />
  1. 添加二级组件
// 设置二级组件
const Topic = ({ match }) => {
    console.log(match);
    return (
        <h3>{match.url}</h3>
    )
};
  1. 完整示范
  • src/views/basic/index.js
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";

// 设置根路由
const BasicExample = () => (
    // 根路由标签
    <Router>
        <div>
            <ul>
                <li>
                    <Link to="/">Home</Link>
                </li>
                <li>
                    <Link to="/topics">Topics</Link>
                </li>
            </ul>

            <hr />
            {/*// 设置跳转的组件*/}
            <Route exact path="/" component={Home} />
            <Route path="/topics" component={Topics} />
        </div>
    </Router>
);
// 设置Home组件
const Home = () => (
    <div>
        <h2>Home</h2>
    </div>
);
// 设置 Topics组件
const Topics = ({ match }) => (
    <div>
        <h2>Topics</h2>
        <ul>
            <li>
                <Link to={`${match.url}/rendering`}>Rendering with React</Link>
            </li>
            <li>
                <Link to={`${match.url}/props-v-state`}>Props v. State</Link>
            </li>
        </ul>
        // 设置一个组件,
        <Route path={`${match.url}/:topicId`} component={Topic} />
        // 设置默认组件
        <Route
            exact
            path={match.url}
            render={() => <h3>Please select a topic.</h3>}
        />
    </div>
);
// 设置二级组件
const Topic = ({ match }) => {
    console.log(match);
    return (
        <h3>{match.url}</h3>
    )
};

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 (
      <div className="App">
          <BasicExample></BasicExample>
      </div>
    );
  }
}
export default App;
  1. redirect 与登录验证
  2. 导入包
import React from "react";
import {
    BrowserRouter as Router,
    Route,
    Link,
    Redirect,
    withRouter
} from "react-router-dom";
  1. 添加路由导航
 <ul>
                <li>
                    <Link to="/public">Public Page</Link>
                </li>
                <li>
                    <Link to="/protected">Protected Page</Link>
                </li>
                <li>
                    <Link to="/logout">logout Page</Link>
                </li>
            </ul>
  1. 添加路由组件
{/*// 定义导航对应组件*/}
            <Route path="/public" component={Public} />
            {/*// 未登录的*/}
            <Route path="/login" component={Login} />
            {/*// 登录后的*/}
            <PrivateRoute path="/logout" component={Logout} />
            <PrivateRoute path="/protected" component={Protected} />
  1. 定义路由组件
  • 验证组件
// 判断是否登录, 如果登录, 则显示传递进来的组件, 否则重定向到登录组件
const PrivateRoute = ({ component: Component, ...rest }) => (
    <Route
        {...rest}
        render={props =>
            fakeAuth.isAuthenticated ? (
                <Component {...props} />
            ) : (
                <Redirect
                    to={{
                        pathname: "/login",
                        state: { from: props.location }
                    }}
                />
            )
        }
    />
);
  • Public组件
  • Protected 组件
const Public = () => <h3>Public</h3>;
const Protected = () => <h3>Protected</h3>;
  • 退出组件
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 (<Redirect
                to={{
                    pathname: "/login",
                    state: { from: this.props.location }
                }}
            />)
        }
        // 未登录则提示登录
        return (
            <div>
                <p>You must log in to view the page at {from.pathname}</p>
                <button onClick={this.logout}>Log out</button>
            </div>
        );
    }
}
  • 登录组件
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 <Redirect to={from} />;
        }
        // 未登录则提示登录
        return (
            <div>
                <p>You must log in to view the page at {from.pathname}</p>
                <button onClick={this.login}>Log in</button>
            </div>
        );
    }
}

  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 }) => (
    <Route
        path={to}
        exact={activeOnlyWhenExact}
        children={({ match }) => {
            return (
                <div className={match ? "active" : ""}>
                 {match ? "> " : ""}
                    <Link to={to}>{label}</Link>
                </div>
            )
        }}
    />
);
  1. 添加导航
<OldSchoolMenuLink activeOnlyWhenExact={true} to="/" label="Home" />
            <OldSchoolMenuLink to="/about" label="About" />
  1. 添加导航对应组件
<Route exact path="/" component={Home} />
            <Route path="/about" component={About} />
  1. 定义组件

const Home = () => (
    <div>
        <h2>Home</h2>
    </div>
);

const About = () => (
    <div>
        <h2>About</h2>
    </div>
);
  1. 完整代码
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
import './index.css'
const CustomLinkExample = () => (
    <Router>
        <div>
            <OldSchoolMenuLink activeOnlyWhenExact={true} to="/" label="Home" />
            <OldSchoolMenuLink to="/about" label="About" />
            <hr />
            <Route exact path="/" component={Home} />
            <Route path="/about" component={About} />
        </div>
    </Router>
);

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

const Home = () => (
    <div>
        <h2>Home</h2>
    </div>
);

const About = () => (
    <div>
        <h2>About</h2>
    </div>
);

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. 添加一级导航
<ul>
                <li>
                    <Link to="/tacos">Tacos</Link>
                </li>
                <li>
                    <Link to="/sandwiches">Sandwiches</Link>
                </li>
            </ul>
  1. 定义一个渲染当前路由配置的组件

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

const RouteWithSubRoutes = route => (
    <Route
        path={route.path}
        render={props =>(
                // pass the sub-routes down to keep nesting
                <route.component {...props} routes={route.routes} />
            )
        }
    />
);
  1. 定义一个循环渲染当前路由数组的组件
  • 该组件值渲染当前数组的一级数组
const renderRoutes = (routes) => {return (routes.map((route, i) => <RouteWithSubRoutes key={i} {...route} />))};
  1. 渲染路由
{renderRoutes(routes)}
  1. 定义一级组件
  • Sandwiches组件
const Sandwiches = () => <h2>Sandwiches</h2>;
  • Tacos组件
const Tacos = ({ routes }) => (
    <div>
        <h2>Tacos</h2>
    </div>
);
  1. 准备渲染二级组件, 在路由配置对象内, 只有tacos组件才有子组件, 因此修改tacos组件
  • 这里添加了 二级导航, 和渲染二级导航对应的组件
  • 这里的routes 是render={props =>(<route.component {...props} routes={route.routes} />) 这里的 routes={route.routes}
  • renderRoutes组件是上面定义的组件, 他会帮我们循环routes数组, 然后渲染出当前数组的一维数组的组件
const Tacos = ({ routes }) => (
    <div>
        <h2>Tacos</h2>
        <ul>
            <li>
                <Link to="/tacos/bus">Bus</Link>
            </li>
            <li>
                <Link to="/tacos/cart">Cart</Link>
            </li>
        </ul>
        {renderRoutes(routes)}
    </div>
);
  1. 定义二级组件
  • Bus
const Bus = () => <h3>Bus</h3>;
  • Cart
const Cart = () => <h3>Cart</h3>;

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

  • Bus
    跟前面的 Tacos 组件一样, 这里添加了三级导航, 并渲染了三级组件
const Bus = ({routes}) => {
    return (
        <div>
            <h3>Bus constructor
                <ul>
                    <li> <Link to="/tacos/bus/bus2">/tacos/bus/bus2</Link> </li>
                    <li> <Link to="/tacos/bus/bus3">/tacos/bus/bus3</Link> </li>
                </ul>
            </h3>
            {renderRoutes(routes)}
        </div>
    )
};
  1. 定义三级组件
const Bus2 = () => <h3>Bus2</h3>;
const Bus3= () => <h3>Bus3</h3>;
  1. 完整代码
import React from "react";
import { BrowserRouter as Router, Route, Link } from "react-router-dom";
// first our route components
const Sandwiches = () => <h2>Sandwiches</h2>;

const Tacos = ({ routes }) => (
    <div>
        <h2>Tacos</h2>
        <ul>
            <li>
                <Link to="/tacos/bus">Bus</Link>
            </li>
            <li>
                <Link to="/tacos/cart">Cart</Link>
            </li>
        </ul>
        {renderRoutes(routes)}
    </div>
);

const renderRoutes = (routes) => {return (routes.map((route, i) => <RouteWithSubRoutes key={i} {...route} />))};

const Bus = ({routes}) => {
    console.log(routes)
    return (
        <div>
            <h3>Bus constructor
                <ul>
                    <li> <Link to="/tacos/bus/bus2">/tacos/bus/bus2</Link> </li>
                    <li> <Link to="/tacos/bus/bus3">/tacos/bus/bus3</Link> </li>
                </ul>
            </h3>
            {renderRoutes(routes)}
        </div>
    )
};
const Bus2 = () => <h3>Bus2</h3>;
const Bus3= () => <h3>Bus3</h3>;
const Cart = () => <h3>Cart</h3>;

////////////////////////////////////////////////////////////
// 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 <Route> and use this everywhere instead, then when
// sub routes are added to any route it'll work
const RouteWithSubRoutes = route => (
    <Route
        path={route.path}
        render={props =>{
            console.log(props)
            console.log(route)
            return (
                // pass the sub-routes down to keep nesting
                <route.component {...props} routes={route.routes} />
            )
        }}
    />
);

const RouteConfigExample = () => (
    <Router>
        <div>
            <ul>
                <li>
                    <Link to="/tacos">Tacos</Link>
                </li>
                <li>
                    <Link to="/sandwiches">Sandwiches</Link>
                </li>
            </ul>

            {renderRoutes(routes)}
        </div>
    </Router>
);

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. 定义一级导航
 <ul>
                <li>
                    <Link to="/tacos">Tacos</Link>
                </li>
                <li>
                    <Link to="/login">login</Link>
                </li>
            </ul>
  1. 定义一级组件
 {routes.map((route, i) => <RouteWithSubRoutes key={i} {...route} />)}
  1. 封装渲染当前组件的组件
const RouteWithSubRoutes = route => (
    <Route
        path={route.path}
        render={props =>{
            return (
                <route.component {...props} routes={route.routes} />
            )
        }}
    />
);
  1. 定义一级组件
  • Login 组件
  • Tacos 组件
const Login = () => <h2>login</h2>;
const Tacos = ({ routes }) => (
    <div >
        <h2>Tacos</h2>
    </div>
);
  1. 根据路由配置, 因为要在 Tacos组件内, 渲染二级组件, 所以需要修改Tacos组件
const Tacos = ({ routes }) => (
    <div >
        <h2>Tacos</h2>
        <ul className="slider">
            {slideMenu(routes)}
        </ul>
        <div className="content">
            {renderRoutes(routes)}
        </div>
    </div>
);
  1. 循环渲染Link组件 slideMenu
  • OldSchoolMenuLink是封装的一层Link, 主要用来匹配当前组件并修改当前选中组件的样式
const slideMenu = (routes) => Array.isArray(routes) && routes.map(item => (
        <li key={item.path}>
            {/*<Link to={item.path}>{item.name}</Link>*/}
            <OldSchoolMenuLink to={item.path} label={item.name} exact={item.exact}></OldSchoolMenuLink>
            {Array.isArray(item.routes) && item.routes.length > 0 && (
                <ul>
                    {slideMenu(item.routes)}
                </ul>
            )}
        </li>
    )
);
  1. 渲染当前路由数组组件
const renderRoutes = (routes) => {return (routes.map((route, i) => <RouteWithSubRoutes key={i} {...route} />))};
  1. 定义二级组件
const Bus= () => <h3>Bus</h3>;
const Cart = () => <h3>Cart</h3>;
  1. 修改 Bus组件
  • renderRoutes 这里会渲染当前组件下面的子组件
const Bus = ({routes}) => {
    return (
        <div>
            <h3>Bus constructor
            </h3>
            {renderRoutes(routes)}
        </div>
    )
};
  1. 定义三级组件
const Bus3= () => <h3>Bus3</h3>;
const Cart = () => <h3>Cart</h3>;
  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 <Route> is a component.

////////////////////////////////////////////////////////////
// first our route components
const Login = () => <h2>login</h2>;

const Tacos = ({ routes }) => (
    <div >
        <h2>Tacos</h2>
        <ul className="slider">
            {slideMenu(routes)}
        </ul>
        <div className="content">
            {renderRoutes(routes)}
        </div>
    </div>
);

const slideMenu = (routes) => Array.isArray(routes) && routes.map(item => (
        <li key={item.path}>
            {/*<Link to={item.path}>{item.name}</Link>*/}
            <OldSchoolMenuLink to={item.path} label={item.name} exact={item.exact}></OldSchoolMenuLink>
            {Array.isArray(item.routes) && item.routes.length > 0 && (
                <ul>
                    {slideMenu(item.routes)}
                </ul>
            )}
        </li>
    )
);


const renderRoutes = (routes) => {return (routes.map((route, i) => <RouteWithSubRoutes key={i} {...route} />))};

const Bus = ({routes}) => {
    return (
        <div>
            <h3>Bus constructor
            </h3>
            {renderRoutes(routes)}
        </div>
    )
};
const Bus2 = () => <h3>Bus2</h3>;
const Bus3= () => <h3>Bus3</h3>;
const Cart = () => <h3>Cart</h3>;

////////////////////////////////////////////////////////////
// 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 }) => (
    <Route
        path={to}
        exact={exact}
        children={({ match }) => {
            return (
                <React.Fragment >
                    {match ? "> " : ""}
                    <Link to={to} className={match ? "active" : ""}>{label}</Link>
                </React.Fragment>
            )
        }}
    />
);


// wrap <Route> and use this everywhere instead, then when
// sub routes are added to any route it'll work
const RouteWithSubRoutes = route => (
    <Route
        path={route.path}
        render={props =>{
            console.log(props)
            console.log(route)
            return (
                // pass the sub-routes down to keep nesting
                <route.component {...props} routes={route.routes} />
            )
        }}
    />
);

const RouteConfigExample = () => (
    <Router>
        <div>
            <ul>
                <li>
                    <Link to="/tacos">Tacos</Link>
                </li>
                <li>
                    <Link to="/login">login</Link>
                </li>
            </ul>
            {routes.map((route, i) => <RouteWithSubRoutes key={i} {...route} />)}
        </div>
    </Router>
);

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

      本文链接:https://www.haomeiwen.com/subject/vtcyoftx.html