美文网首页
React进阶篇(九)React Router

React进阶篇(九)React Router

作者: 娜姐聊前端 | 来源:发表于2020-05-06 21:24 被阅读0次

    单页面应用(SPA)可以让Web应用看起来像多页面应用,URL变化时,不会向服务端发起请求,而是利用自身监听路由变化而更新UI。
    通过使用React Router可以让Web应用根据不同URL渲染不同组件。

    下面所以内容基于React Router 4。

    1. 路由器

    React Router通过 RouterRoute两个组件完成路由功能。

    • Router:路由器。一个应用只需要一个Router。
    • Route:路由配置。其为Router的子组件。

    路由方式有两种(都是Router的子组件)

    • BrowserRouter:使用Html5 的History API(pushState, replaceState等)实现I和URL同步
    http://example.com/some/path
    

    使用BrowserRouter,需要对服务器进行配置,让服务器能处理所有可能正确的URL(需要服务器返回SPA应用中唯一的HTML页面)

    • HashRouter:使用URL的Hash实现I和URL同步
    http://example.com/#/some/path
    

    使用HashRouter,无需服务器配置

    2. 路由配置

    • path:用来描述这个Route匹配的URL路径
    • match:当URL和Route匹配时,Route会创建一个match对象作为props中的一个属性传递给被渲染的组件。
    match {
        params, // 参数,如<Route path='/foo/:id'>,那么,当URL为'http://example.com/foo/1'时,params = {id: 1}
        isExact, // boolean值。是否完全匹配
        path, // Route的path属性
        url // URL的匹配部分
    }
    

    3. Route渲染组件

    • 方式一:component
    <Route path='/foo' component={Foo}>
    
    • 方式二:render(可以向组件传递额外属性;每次路由到都会创建新的组件)
    <Route path='/foo' render={props=><Foo {...props} data={extraData}/>}>
    
    • 方式三:children(无论是否匹配成功,children返回的组件都会被渲染)
    <Route path='/foo' childern={props=>
        <div className={props.match ? 'active': ''}>
            <Foo />
        </div>}>
    

    4. switch和exact (React Router 4)

    当URL和多个Route匹配时,如果只想让第一个匹配的Route渲染,那么可以将这个Route放在Switch组件中。

    如果想让Route和URL完全匹配时,才渲染Route,那么使用exact属性。

    <Router>
        <Switch>
            <Route exact path='/' component={Home} />
            <Route path='/posts' component={Post} /> 
            <Route path='/:user' component={User}/ >
        </Switch>    
    </Router>
    
    
    

    5. 嵌套路由

    在Route渲染的组件内部定义新的Route。比如,改造上面的Post路由组件:

    const Post = (match=>{
        return (
            <div>
                <Route path={`${match.url}/:id`} component={PostDetail} />
                <Route exact path={match.url} component={PostList} >
            </div>
        )
    })
    

    6. 链接

    • Link组件
    <Link to={{
        pathname: '/post',
        search: '?sort=name',
        hash: '#hash',
        state: {name: 'React'} // 传递数据
    }}>
    
    • JS操作
    this.props.history.push('/post');
    this.props.history.replace('/post');
    

    Demo

    基于Antd和React Route 4。

    现在有两个页面:

    • 登录页Login,不带有导航栏
    • 主页Home,带导航栏
    • 页面Child,带导航栏

    用户先通过登录页面登录,然后自动跳转到主页。

    1. 定义路由配置routes.js
    import React from 'react';
    
    import BasicLayout from '@/layouts/BasicLayout';
    import UserLayout from '@/layouts/UserLayout';
    
    const Home = React.lazy(() => import('@/pages/Home));
    const Child = React.lazy(() => import('@/pages/Child'));
    const NotFound = React.lazy(() => import('@/pages/NotFound'));
    
    const routerConfig = [
        {
            path: '/user',
            component: UserLayout,
            children: [
                {
                    path: '/login',
                    component: UserLogin
                },
                {
                    path: '/',
                    redirect: '/user/login', // 如果路径为 /user,会重定向到/user/login
                },
                {
                    component: NotFound,
                },
            ]
        },
        {
            path: '/',
            component: BasicLayout,
            children: [
                {
                    path: '/home',
                    component: Home
                },
                {
                    path: '/page/:id',
                    component: Child
                },
                {
                    path: '/',
                    redirect: '/home',
                },
            ]
        }
    ];
    
    export default routerConfig;
    
    2. 定义BasicLayout上使用的菜单menu.js
    export const asideMenuConfig = [
        {
            name: 'Home',
            path: '/home',
            icon: 'home',
            key: 1
        },
        {
            name: 'Child',
            path: '/page',
            icon: 'book',
            key: 2
        }
    ]
    
    3. 定义导航BasicLayout.js
    import React, { useState } from 'react';
    import { Layout, Menu, Icon } from 'antd';
    import { Link } from 'react-router-dom';
    
    import logo from '@/components/images/logo.png';
    import { asideMenuConfig } from '@/config/menu';
    
    const { Content, Sider } = Layout;
    
    export default (props) => {
    
        const [collapsed, setCollapsed] = useState(0);
    
        function getActiveItemKey() {
            let hash = window.location.hash;
            const path = hash.substring(1);
            const route = asideMenuConfig.filter(item => path === item.path);
            if (route.length > 0) {
                return [route[0].key + ''];
            }
            return ['1'];
        }
    
        return (
            <Layout style={{ minHeight: '100vh' }}>
                <Sider
                    collapsible
                    collapsed={collapsed}
                    onCollapse={() => setCollapsed(!collapsed)}
                >
                    {collapsed && <div style={{ textAlign: 'center', padding: '20px 0 20px' }}>
                        <img src={logo} alt='积木盒子' width={65} />
                    </div>}
                    {!collapsed && <div className="logo"><img src={logo} alt='积木盒子' /></div>}
                    <Menu theme="dark" defaultSelectedKeys={getActiveItemKey()} mode="inline">
                        {asideMenuConfig.map(item =>
                            <Menu.Item key={item.key}>
                                <Link to={item.path}><span><Icon type={item.icon} /><span>{item.name}</span></span></Link>
                            </Menu.Item>
                        )}
                    </Menu>
                </Sider>
                <Layout>
                    {/*<Header>it is nothting</Header>*/}
                    <Content style={{ position: 'relative' }}>
                        {props.children}
                    </Content>
                </Layout>
            </Layout>
        )
    }
    
    4. 定义路由MyRouter.js
    /**
     * Created by yelan on 2018/10/1.
     */
    
    import React, { Suspense } from 'react';
    import path from 'path';
    import { HashRouter as Router, Route, Switch, Redirect } from 'react-router-dom';
    import PageLoading from '@/components/PageLoading';
    import routes from './config/routes';
    
    const RouteItem = (props) => {
        const { redirect, path: routePath, component, key } = props;
        if (redirect) {
            return (
                <Redirect
                    exact
                    key={key}
                    from={routePath}
                    to={redirect}
                />
            );
        }
        return (
            <Route
                key={key}
                component={component}
                path={routePath}
            />
        );
    };
    
    export default () => {
    
        return (
            <Router>
                <Switch>
                    {
                        routes.map((route, id) => {
                            const { component: RouteComponent, children, ...others } = route;
    
                            return (
                                <Route
                                    key={id}
                                    {...others}
                                    component={props => {
                                        return (
                                            children ? (
                                                <RouteComponent key={id} {...props}>
                                                    <Suspense fallback={<PageLoading />}>
                                                            <Switch>
                                                                {children.map((routeChild, idx) => {
                                                                    const { redirect, path: childPath, component } = routeChild;
                                                                    return RouteItem({
                                                                        key: `${id}-${idx}`,
                                                                        redirect,
                                                                        path: childPath && path.join(route.path, childPath),
                                                                        component
                                                                    })
                                                                })}
                                                            </Switch>
                                                     </Suspense>
                                                </RouteComponent>
                                            ) : (
                                                    <Suspense fallback={<PageLoading />}>
                                                            {
                                                                RouteItem({
                                                                    key: id,
                                                                    ...route
                                                                })
                                                            }
                                                   </Suspense>
                                                )
                                        )
                                    }}
                                ></Route>
                            )
                        })
                    }
                </Switch>
            </Router>
        )
    }
    

    相关文章

      网友评论

          本文标题:React进阶篇(九)React Router

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