React路由

110 阅读3分钟
  • 不同的路径渲染不同的组件

  • 有两种实现方式

    • HashRouter:利用hash实现路由切换
    • BrowserRouter:实现h5 Api实现路由的切换

    HashRouter

  • 利用hash实现路由切换

public\index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <style>
        #root{
            border:1px solid red;
        }
    </style>
</head>
<body>
    <div id="root"></div>
    <ul>
        <li><a href="#/a">/a</a></li>
        <li><a href="#/b">/b</a></li>
    </ul>
    <script>
        window.addEventListener('hashchange',()=>{
            console.log(window.location.hash);
            let pathname = window.location.hash.slice(1);//把最前面的那个#删除 
            root.innerHTML = pathname;
        });

    </script>
</body>
</html>

BrowserRouter

  • 利用h5 Api实现路由的切换

history

  • HTML5规范给我们提供了一个history接口
  • HTML5 History API包括2个方法:history.pushState()history.replaceState(),和1个事件window.onpopstate
pushState
  • history.pushState(stateObject, title, url),包括三个参数

    • 第一个参数用于存储该url对应的状态对象,该对象可在onpopstate事件中获取,也可在history对象中获取
    • 第二个参数是标题,目前浏览器并未实现
    • 第三个参数则是设定的url
  • pushState函数向浏览器的历史堆栈压入一个url为设定值的记录,并改变历史堆栈的当前指针至栈顶

replaceState
  • 该接口与pushState参数相同,含义也相同
  • 唯一的区别在于replaceState是替换浏览器历史堆栈的当前历史记录为设定的url
  • 需要注意的是replaceState不会改动浏览器历史堆栈的当前指针
onpopstate
  • 该事件是window的属性
  • 该事件会在调用浏览器的前进、后退以及执行history.forwardhistory.back、和history.go触发,因为这些操作有一个共性,即修改了历史堆栈的当前指针
  • 在不改变document的前提下,一旦当前指针改变则会触发onpopstate事件

路由的钩子函数

  • useHistory,这个钩子可以访问history,可以更好的进行导航
  • useLocation, 此钩子可以返回location表示当前URL对象
  • useParams, 返回URL参数的键值对的对象
  • useRouteMatch 此钩子可以精准匹配路由然后显示对应的页面
import React from 'react';
import ReactDOM from 'react-dom';
import {
  BrowserRouter as Router, Route, Link,
  useHistory,
  useLocation,
  useParams,
  useRouteMatch
} from './react-router-dom';

function Home() {
  return <div>Home</div>
}
function UserDetail(props) {
  console.log('props.match', props.match);
  console.log('props.match.params', props.match.params);
  // history location match{params}
  let params = useParams();//它会用当前组件的路径 进行匹配,不能传参
  console.log('params', params);
  let history = useHistory();
  console.log('history', history);
  let location = useLocation();
  console.log('location', location);
  //这个可以传递路径,想传什么路径就传什么路径
  let match = useRouteMatch({ path: '/user/detail/:id', strict: false, sensitive: false });
  console.log('useRouteMatch', match);
  console.log('useRouteMatch.params', match.params);
  return <div>UserDetail</div>
}
ReactDOM.render(
  <Router>
    <ul>
      <li><Link to="/" exact={true}>首页</Link></li>
      <li><Link to={{ pathname: '/user/detail/100', state: { id: 100, name: '张三' } }}>用户100详情</Link></li>
    </ul>
    <Route path="/" exact={true} component={Home} />
    <Route path="/user/detail/:id" component={UserDetail} />
  </Router>,
  document.getElementById('root')

懒加载

  • 懒加载返回的必须要是一个promise
const LazyFoo = React.lazy(() => import('./components/Foo'));

function lazy(dynamicImport) {
  return function () {
    let [Component, setComponent] = React.useState(null);
    React.useEffect(() => {
      dynamicImport().then(result => {
        let LazyComponent = result.default;
        setComponent(LazyComponent)
      });
    }, []);
    return Component && <Component />;
  }
}

-v6

Switch重命名为Routes 

  • component/renderelement替代
  • RoutesRoute基于当前位置在React Router中渲染某些内容的主要方法
  • 您可以把Route考虑为一种类似于if语句的路由,如果其路径与当前URL匹配,则呈现其元素
  • Route的caseSensitive属性属性确定是否应以区分大小写的方式进行匹配(默认为false)
function App() {
  let [routes, setRoutes] = React.useState(routesConfig);
  return (
    <div>
      {useRoutes(routes)}
    </div>
  )
}

配置文件routesConfig

const routesConfig = [
    { path: '/', element: <Home />, index: 0 },
    {
        path: '/user/*',
        element: <User />,
        index: 1,
        children: [
            { path: 'add', element: <UserAdd />, index: 0 },
            { path: 'list', element: <UserList />, index: 1 },
            { path: 'detail/:id', element: <UserDetail />, index: 2 }
        ]
    },
    { path: '/foo', element: <Foo /> }
]
export default routesConfig;

用useNavigate代替useHistory

  • useNavigate钩子返回一个函数,该函数允许您以编程方式进行导航
function Home() {
    let navigate = useNavigate();

    function navigateToUser() {
        navigate('/user');
    };
    return (
        <div>
            <p>Home</p>
            <button onClick={navigateToUser}>跳转到/user</button>
        </div>
    )
}

Redirect 标签删除

  • 解决方案:新版的路由需要引入标签
  • Navigate元素在渲染时更改当前位置
<Router>
    <Routes>
        <Route path='/login' element={<Login/>}/>
        <Route path='/admin' element={<Admin/>}/>
        // 重定向到login
        <Route path="*" element={<Navigate to="/login" />} />
    </Routes>
</Router>