react-router-dom升级v6

此次版本升级涉及改动较多,且不向下兼容

1. Switch组件换为Routes, Route组件的render换为element
// old
import {
  Route, Switch, withRouter,
} from 'react-router-dom';

<Switch>
  {routes.map(
    ({path, exact, component: Component, routes: Routes}) => (
      <Route
        key={path}
        path={path}
        exact={exact}
        render={props => <Component {...props} routes={Routes} />}
      />),
    )}
  <Route render={props => <NoMatch {...props} />} />
</Switch>

// new
import {
  Route, Routes, Navigate,
} from 'react-router-dom';
<Routes>
  {routes.map(
   ({path, component: Component, children}) => (
    <Route
      key={path}
      path={path}
      element={<Component {...props} />}
    >
      // 子路由的写法,之前可以写在组件中的嵌套Switch中
      {children && children.map(({ path, component: Component }) => {
        if (path === '/wealth/set') {
          return (<Route 
            element={<Navigate to="/wealth/set/mechanismset" />}
            path="/wealth/set" 
          />)}
        return (
          <Route
            key={path}
            path={path}
            element={<Component {...props} />}
          />)
        })}
      </Route> )
    )}
  <Route render={(props) => <NoMatch {...props} />} />
</Routes>

2. Redirect组件废弃
// old
if(route.path == '/wealth/set'){
  return <Redirect to={tabs[0].key} />
}

// new
<Route 
  element={<Navigate to={tabs[0].key} />}
  path="/wealth/set" 
/>
3.子路由的渲染及Outlet的使用
// old直接子组件中放Switch
//App.js
<Switch>
  {routes.map(
    ({path, exact, component: Component, routes: Routes}) => (
      <Route
        key={path}
        path={path}
        exact={exact}
        render={props => <Component {...props} routes={Routes} />}
      />),
  )}
  <Route render={props => <NoMatch {...props} />} />
</Switch>

// child.js
<Switch>
  {
    // App.js 拿到传过来的值,并循环配置路由
    this.props.routes.map((route, key) => {
      if (route.path == '/wealth/set') {
        return <Redirect to={tabs[0].key} key={key} />
      }
      return <Route key={key} exact={route.exact} path={route.path} render={(props) => <route.component {...props} />} />
    })
  }
</Switch>

// new app中嵌套路由,由Outlet做展示
// App.js
<Routes>
  {routes.map(
   ({path, component: Component, children}) => (
    <Route
      key={path}
      path={path}
      element={<Component {...props} />}
    >
      // 子路由的写法,之前可以写在组件中的嵌套Switch中
      {children && children.map(({ path, component: Component }) => {
        if (path === '/wealth/set') {
          return (<Route 
            element={<Navigate to="/wealth/set/mechanismset" />}
            path="/wealth/set" 
          />)}
        return (
          <Route
            key={path}
            path={path}
            element={<Component {...props} />}
          />)
        })}
      </Route> )
    )}
  <Route render={(props) => <NoMatch {...props} />} />
</Routes>
// child.js
<Outlet {...this.props} />

4. withRouter废弃
// 实现withRouter
import React from 'react';
import { useLocation, useNavigate, useParams } from 'react-router-dom';

export default function withRouter(Child) {
    return function(props) {
      const location = useLocation();
      const navigate = useNavigate();
      const params = useParams();
      return <Child {...props} navigate={navigate} params={params} location={location} />;
    }
  }

5. Prompt废弃

重写BrowserRouter,替换'react-router-dom'的BrowserRouter

// 需要先给BrowserRouter注入history对象
import React from 'react';
import { createBrowserHistory } from "history";

import { Router } from "react-router";


const browserHistory = createBrowserHistory({ window });

const BrowserRouter = ({
    basename,
    children,
    window,
}) => {
    let historyRef = React.useRef();
    if (historyRef.current == null) {
        historyRef.current = browserHistory;
    }

    let history = historyRef.current;
    let [state, setState] = React.useState({
        action: history.action,
        location: history.location,
    });

    React.useLayoutEffect(() => history.listen(setState), [history]);

    return (
        <Router
            basename={basename}
            children={children}
            location={state.location}
            navigationType={state.action}
            navigator={history}
        />
    );
}

export {
    browserHistory as history,
    BrowserRouter
}

实现Prompt

import React, { useEffect } from 'react';
import {history} from '../BrowserRouter';
import {useLocation, useNavigate} from 'react-router-dom';


const Prompt = (props) => {
    const location = useLocation();
    const navigate = useNavigate();

    // 存储关闭阻止页面切换的方法(调用此方法将关闭阻止页面切换)
    let unblock = null;

    // 阻止页面卸载
    const beforeUnload = (event) => {
        event.preventDefault();
        event.returnValue = '';
    }

    // 页面切换时的回调
    const handlePageChange = async ({location,action}) => {
        // 是否关闭切换限制并跳转
        let toNext = false;

        if (props.message) {
            if (typeof props.message === "string") {
                toNext = confirm(props.message);
            } else {
                toNext = await props.message(location,action);
            }
        } else {
            toNext = confirm("是否放弃更改");
        }

        toNext && closeBlockAndNavigate(nextLocation);
    }

    // 关闭阻止页面切换
    const closeBlockPageSwitching = () => {
        if (unblock) {
            unblock();
            unblock = null;
            window.removeEventListener("beforeunload", beforeUnload);
        }
    }

    // 关闭阻止页面切换,并跳转
    const closeBlockAndNavigate = (nextLocation) => {
        closeBlockPageSwitching();
        navigate(nextLocation);
    }

    // 监听when 和 pathname 变化,当发生变化时判断是否需要开启block navigate.
    useEffect(() => {
        if (props.when) {
            // 阻塞页面跳转(history行为)
            unblock = history.block(handlePageChange);
            window.addEventListener('beforeunload', beforeUnload);
        }
        return () => {
            props.when && closeBlockPageSwitching();
        }
    }, [props.when, location.pathname]);

    return (
        <></>
    );
}

export default Prompt;

6. history对象废弃,路由跳转使用navigate代替
// old
history.go(n)
history.goBack()
history.goForward()
history.push(location);
history.replace(location);
// new
navigate(-1); // history.goBack();
navigate(1); // history.goForward();
navigate(location); // history.push(location);
navigate(location, { replace: true });  // history.replace(location);
7. 路由传参方式修改及参数获取方式
// old
history.push({
  pathname: '/home',
  search: qs.stringify({ the: 'query' }),
  state: { some: 'state' },
  query: 'state'
});
history.push( '/home',{ some: 'state' })
//取值
const {pathname, hash, state, search, query} = history.location;

// new
navigate( '/home', {state: {some: 'state' },replace: true,})
navigate({ pathname: '/home', search: qs.stringify({ the: 'query' }) })}

const { state, pathname, search} = this.props.location;
8. 删除match对象
// old
const {params, url, path, isExact} = this.props.match;

// new 
const { params } = this.props;
const { state, pathname, search} = this.props.location;
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,470评论 6 501
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,393评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,577评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,176评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,189评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,155评论 1 299
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,041评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,903评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,319评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,539评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,703评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,417评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,013评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,664评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,818评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,711评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,601评论 2 353

推荐阅读更多精彩内容