美文网首页
react-router-dom升级v6

react-router-dom升级v6

作者: Mr无愧于心 | 来源:发表于2022-07-04 17:56 被阅读0次

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

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;

相关文章

网友评论

      本文标题:react-router-dom升级v6

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