React router(V6以下)

嵌套路由

  1. 在Route中使用render嵌套(v4版本)
   <Route path='/Comp1' render={props => <Comp1 {...props}>
             <Route index path={`/Comp1/Son1`} component={Son1} />
             <Route path={`/Comp1/Son2`} component={Son2} />
          </Comp1>}>
   </Route>
  1. 外部组件实现嵌套
//父组件内 这里不要加exact
<Route path='/Comp1' component={Comp1} />
//Comp1组件内 路径可以写成动态的`${path}/Son1`,path从props.match中获取
<Link to={`Comp1/Son1`}>Son1</Link>
<Link to={`Comp1/Son2`}>Son2</Link>
<Route path={`Comp1/Son1`} component={Son1} />
<Route path={`Comp1/Son2`} component={Son2} />

默认路由:

  1. 可以使用重定向Redirect实现
function App() {
  return (
    <div className="App">
      <Router>
        <Main>
          <Menus />
          <Switch>
            <Route path={"/home"} component={Home}></Route>
            <Route path={"/list"} component={List}></Route>
            <Route path={"/children"} component={Children}></Route>
            <Redirect to='/home' /> //这里一进入页面会默认匹配home,需要放到最后,前面不匹配时才匹配这个
          </Switch>
        </Main>
      </Router>
    </div>
  );
}
  1. 增加一个路由,component为默认路由组件
function App() {
  return (
    <div className="App">
      <Router>
        <Main>
          <Menus />
          <Switch>
            <Route exact path={"/"} component={Children}></Route> 默认展示Children组件,注意需要加exact,否则后面路由不生效
            <Route exact path={"/home"} component={Home}></Route>
            <Route exact path={"/list"} component={List}></Route>
            <Route path={"/children"} component={Children}></Route>
          </Switch>
        </Main>
      </Router>
    </div>
  );
}

嵌套路由的情况

//父路由
<Route path={"/children"} component={Children}></Route>

//子路由
const Children = () => {
  return (
    <div>
      <h2>我是children组件</h2>
      <nav>
        <Link to={"/children/children1"}>children页面</Link>
        <Link to={"/children/children2"}>children页面</Link>
      </nav>
      <Route exact path={"/children/"} component={Children1}></Route>这里path等于'/children/'或者'/children'都可以,但是需要严格匹配
      <Route path={"/children/children1"} component={Children1}></Route>
      <Route path={"/children/children2"} component={Children2}></Route>
    </div>
  );
};
  • 注意:v4还不支持Router中嵌套多个子组件,只能有一个根元素,否则就会报错
    后台报错

动态传参

1. params传参(不好用)
①Route path后用 冒号 + key 拼接,用 / 隔开多个参数;
②Link 接收参数,并传入参数值;

//Route和Link中的值一一对应
 <Route exact path='/Comp2/:id/:name' component={Comp2} />
 <Link to='/Comp2/123/xiaowang'>Comp2</Link>

使用方法:在Comp2组件内部通过props.match.params可以拿到参数
这里打印的是props

优点:刷新页面参数不丢失。
缺点:①只能传递字符串,没办法直接传递对象,只能通过JSON.stringify转换为JSON对象再转换回来(JSON.parse)的方式传递。
②参数会拼接到地址栏,传递过多参数url会变得很长,同时也缺乏安全性。
③参数必须在路由上配置。
在这里插入图片描述

(解决不能传Object的问题)通过JSON.stringify和JSON.parse转换对象

 const data={'name':'xw',age:18}
<Route exact path='/Comp2/:data' component={Comp2} />
<Link to={`/Comp2/${JSON.stringify(data)}`}>Comp2</Link>
//Comp2中获取
console.log(props,JSON.parse(props.match.params.data));

在这里插入图片描述

2. 通过query传参(更方便)
①将Link中的to的属性值传为一个包含pathname(n小写)和参数的对象
②使用时通过props.location.query获取

<Route exact path='/Comp2' component={Comp2} />

//Link
 const data = { 'name': 'xw', age: 18 }
  const path = {
    pathname: '/Comp2',
    query: data
  }
 <Link to={path}>Comp2</Link> 
 //获取
 console.log(props.location.query);

在这里插入图片描述

优点:不拼接参数到地址栏,传参方便,不限制传参类型
缺点:刷新页面参数丢失。

在这里插入图片描述

3. 通过state传值(最好用)
将上述query对象中的参数名改为state即可,通过props.location.state获取

<Route exact path='/Comp2' component={Comp2} />

//Link
 const data = { 'name': 'xw', age: 18 }
  const path = {
    pathname: '/Comp2',
    state: data
  }
 <Link to={path}>Comp2</Link> 
 //获取
 console.log(props.location.state);

在这里插入图片描述

同时具备上述两个方法的优点。
①参数不拼接到url后面,非明文方式传参更安全。
②使用方便。
③刷新页面参数不丢失。

在这里插入图片描述

React-Router Hook

  • 注意:你必须使用 react@16.8+ 且 react-router-dom@5+ 才能使用这些 hooks!
  1. useHistory

可以获取到history对象

import {
  Route,
  useHistory,
} from "react-router-dom";
const Children=()=>{
 let history = useHistory();
  const handleClick = () => {
    console.log(history);
    history.push("/list");
  };
  return(
    <button type="button" onClick={handleClick}>跳转</button>
  )
}

在这里插入图片描述

  1. useLocation

返回当前url的location对象(属于windows内置对象),可以返回实时的loacation对象,上面有一些内置方法go、push、replace以及传过来的参数等等。

版本

5.3.4版本

  1. useParams

返回params方式传递的参数对象(拼接在url后面的参数的对象),当前对应的match.params。

//路由
<Link to={'/children/xw/18'}>children页面</Link>
<Route path={"/children/:name/:age"} component={Children}></Route>
 
//Children组件
import {
  useParams
} from "react-router-dom";
 let {name,age} =useParams();
 console.log('params',name,age);

在这里插入图片描述

  1. useRouteMatch

可以以的方式去匹配当前的url,返回的是match对象。例如嵌套路由中子路由的path可以通过useRouteMatch获取到父路由的path,再拼接得到。

在这里插入图片描述
useRouteMatch返回的对象是props里面的match对象。

import {
  useRouteMatch
} from "react-router-dom";

//父路由
<Route path={"/children/:name/:age"} component={Children}></Route>

//子路由
let match=useRouteMatch();
<Link to={`${match.path}/children1`}>children页面</Link>
<Link to={`${match.path}/children2`}>children页面</Link>
<Route path={`${match.path}/children1`} component={Children1}></Route>
<Route path={`${match.path}/children2`} component={Children2}></Route>
  • useRouteMatch还可以接收参数,参数是的path属性对象;
useRouteMatch({
 path:'/home',
 strict:true, //严格匹配
 sensitive:true //区分大小写
})

动态路由

  • 利用antd+react-router+pubsub写了一个demo,gitee地址(目前只更新了V6以下的版本)。
    在这里插入图片描述
    代码目录:
    oldVersion是V6以下版本(我用的是v5),newVersion之后会更新V6版本
    在这里插入图片描述
    依赖版本:
    在这里插入图片描述
  1. 主入口
import React, { Suspense } from "react";
import config from "./oldVersion/dynamicRouter/config";
import { BrowserRouter as Router } from "react-router-dom";
import { Layout } from "antd";
import RouteMenu from "./oldVersion/Menus";
import { RouteWithSubRoutes } from "./utill";

const { Sider } = Layout;
//左右结构,侧边栏Slider,右边另一块Layout
const DynamicRouter = () => {
  return (
    <Router>
      <Layout>
        <Sider width={200} className="site-layout-background">
          <RouteMenu /> //路由菜单<Link> <NavLink>
        </Sider>
        <Layout style={{ padding: "0 24px 24px" }}>
          <Suspense fallback={<div>loading...</div>}>  //这里用懒加载按需引用模块
            {config.map((route, i) => (
              <RouteWithSubRoutes key={i} {...route} /> //根据路由配置文件遍历选择路由
            ))}
          </Suspense>
        </Layout>
      </Layout>
    </Router>
  );
};

export default DynamicRouter;
  1. 路由配置文件
import React, { lazy } from "react";
import {
  SmileTwoTone,
  ProfileTwoTone,
  ContactsTwoTone,
  GithubOutlined,
  TwitterOutlined,
} from "@ant-design/icons";

//懒加载引入组件
const handleLazy = (name) => {
  return lazy(() => import(`../${name}`));
};

const config = [
  {
    key: "sub1",
    label: "首页", //用key、label、icon是为了用antd的Menu组件
    icon: <SmileTwoTone />, 
    path: "/home",
    component: handleLazy("Home"), //注意:component对应的应该是callback,否则无法匹配<Route>
    exact: true,
  },
  {
    key: "sub2",
    label: "列表",
    icon: <ProfileTwoTone />,
    path: "/list",
    component: handleLazy("List"),
    exact: true,
  },
  {
    key: "sub3",
    label: "人员",
    icon: <ContactsTwoTone />,
    path: "/children",
    component: handleLazy("Children"),
    exact: false,
    children: [
      {
        key: "children1",
        label: "人员1",
        icon: <GithubOutlined />,
        path: "/children/children1",
        component: handleLazy("Children1"),
        exact: true,
      },
      {
        key: "children2",
        icon: <TwitterOutlined />,
        label: "人员2",
        path: "/children/children2",
        component: handleLazy("Children2"),
        exact: true,
      },
    ],
  },
];

export default config;

  1. RouteMenu 路由菜单
import React, { useState, useEffect } from "react";
import { Link } from "react-router-dom";
import { Menu } from "antd";
import config from "../oldVersion/dynamicRouter/config";
import PubSub from "pubsub-js";

const Menus = () => {
  const [selectedKeys, setSelectedKeys] = useState([]);

//这里用递归处理一下配置文件中的label,使得他们被<Link>包裹(否则用不了路由)
  const handleLable = (value) => {
    return value.children
      ? {
          ...value,
          children: value.children.map((child) => handleLable(child)),
        }
      : {
          ...value,
          label: <Link to={value.path}>{value.label}</Link>,
        };
  };

  useEffect(() => {
  //订阅backtohome这条消息
    PubSub.subscribe("backtohome", (_, data) => {
      setSelectedKeys([data]); //点击人员中的按钮返回首页
    });
  }, []);

  return (
    <Menu
      mode="inline"
      defaultOpenKeys={[config[0].key]}
      selectedKeys={selectedKeys}
      onClick={(v) => setSelectedKeys([v.key])}
      style={{
        height: "100%",
        borderRight: 0,
      }}
      items={config.map((i) => handleLable(i))}
    ></Menu>
  );
};

export default Menus;

  1. Children(嵌套路由)
import React from "react";
import {
  useHistory,
} from "react-router-dom";
import { HomeOutlined } from "@ant-design/icons";
import { Button, Tooltip } from "antd";
import PubSub from 'pubsub-js';
import {RouteWithSubRoutes} from '../utill';

const Children = (props) => {
  let history = useHistory();
  
  //点击返回首页
  const handleClick = () => {
  //发布backtohome使得Menu更新界面
    PubSub.publish('backtohome','sub1');
    history.push("/home");//更新路由
  };

  return (
    <div>
      <h2>我是children组件</h2>
      {props.children.length > 0 &&
        props.children.map((route, i) => (
          <RouteWithSubRoutes key={i} {...route} /> //遍历出子路由,我需要子路由显示在这里,所以在这里遍历(Route与它对应的Link应该在同一层级,比如Link是最外层,那么对应的Route应该也应该是最外层,不应该被其他Route包裹)
        ))}
      <div style={{width:'100%',textAlign:'right'}}>
        <Tooltip title="返回首页">
          <Button type="primary" shape="circle" icon={<HomeOutlined />} onClick={handleClick} />
        </Tooltip>
      </div>
    </div>
  );
};

export default Children;

  1. utill.js(公共方法)
import { Route, Redirect } from "react-router-dom";

/*
根据路由配置选择Route
*/
const RouteWithSubRoutes = (route) => {
  if (!route.path) return <Route component={NotFound} />;
  return (
    <Route
      exact={route.exact}
      strict
      path={route.path}
      render={(props) => //render的意思其实就是当path对应上以后,当前Route需要渲染成什么样子,你可以自己定义,需要注意的是这三个属性的优先级(component>render>children),所以你不能同时使用
        route.redirect ? (
          <Redirect push to={route.redirect} from={route.path}></Redirect>
        ) : (
          <route.component {...props} children={route.children} /> //route.component对应着配置文件中按需引入的component,如果component不是callback这里会报错
        )
      }
    />
  );
};

const NotFound = () => {
    return <div>抱歉,页面丢失啦</div>;
  };

export { RouteWithSubRoutes };

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值