【REACT-路由v6】


2021年11月 react router 6 成为默认版本,npm安装时自动安装6版本
npm i react-router-dom

1. App.js

import './App.css';
import { HashRouter } from 'react-router-dom';//路由模式BrowserRouter
import IndexRouter from './router/IndexRouter';
import Tabbar from './components/Tabbar/Tabbar';

function App() {
  return (
    <div className="App">
      <li>dddd</li>
      <HashRouter>
        <IndexRouter></IndexRouter>
        <Tabbar></Tabbar>
      </HashRouter>
    </div>
  );
}

export default App;

2. 搭建路由

src/router/IndexRouter.js

2.1 普通写法

import React, { lazy, Suspense } from 'react'
import {Routes,Route,Navigate} from 'react-router-dom'
import Redirect from '../components/Redirect'

export default function IndexRouter() {
  return (
    <Routes>

      {/* index等同于他的父级地址,这里等同于http://localhost:3000/ */}
      {/* <Route index element={<Films/>} /> */}

      <Route path='/films' element={LazyLoad('Films')}>
        <Route index element={<Navigate to="/films/nowPlaying" />} />
        {/* 嵌套路由需要在组件Films中配套Outlet(出口)一起使用 */}
        <Route path='nowPlaying' element={LazyLoad('films/NowPlaying')} />
        <Route path='/films/commingSoon' element={LazyLoad('films/CommingSoon')} />
      </Route>

      <Route path='/cinemas' element={LazyLoad('Cinemas')} />
      <Route path='/login' element={LazyLoad('Login')} />
      <Route path='/center' element={<AuthCom>{LazyLoad('Center')}</AuthCom>} />

      {/* <Route path='/detail' element={LazyLoad('DetailsSearch)} /> */}
      <Route path='/detail/:id/:type' element={LazyLoad('DetailsParams')} />

      {/* 重定向-Navigate:星号可以匹配任意地址*/}
      {/* <Route path="/"  element={<Navigate to="/films" />}/> */}
      <Route path="/"  element={<Redirect to="/films" />}/>
      <Route path="*"  element={LazyLoad('NotFound')}/>

    </Routes>
  )
}

//路由拦截
function AuthCom({children}){//props.children
  const isLogin = window.localStorage.getItem('token');
  return isLogin?children:<Redirect to="/login"/>
}

//路由懒加载,重定向的不用再调用懒加载函数
const LazyLoad = path => {
  const Comp = lazy(()=>import('../views/'+path));
  return (
    <Suspense fallback={<>加载中。。。</>}>
      <Comp/>
    </Suspense>
  )
}

2.2 使用useRoutes构建路由

import React, { lazy, Suspense } from 'react'
import {Routes,Route,Navigate, useRoutes} from 'react-router-dom'
import Redirect from '../components/Redirect'

export default function IndexRouter() {
  const element = useRoutes([
    {
      path:'/films',
      element:LazyLoad('Films'),
      children:[
        {
          path:'',
          element:<Navigate to="/films/nowPlaying" />
        },
        {
          path:'nowPlaying',
          element:LazyLoad('films/NowPlaying')
        },
        {
          path:'/films/commingSoon',
          element:LazyLoad('films/CommingSoon')
        },
      ]
    },
    {
      path:'/cinemas',
      element:LazyLoad('Cinemas')
    },
    {
      path:'/login',
      element:LazyLoad('Login')
    },
    {
      path:'/center',
      element:<AuthCom>{LazyLoad('Center')}</AuthCom>
    },
    {
      path:'/detail/:id/:type',
      element:LazyLoad('DetailsParams')
    },
    {
      path:'/',
      element:<Redirect to="/films" />
    },
    {
      path:'*',
      element:LazyLoad('NotFound')
    },
  ]);
  return (
    element
  )
}

//路由拦截
function AuthCom({children}){//props.children
  const isLogin = window.localStorage.getItem('token');
  return isLogin?children:<Redirect to="/login"/>
}

//路由懒加载,重定向的不用再调用懒加载函数
const LazyLoad = path => {
  const Comp = lazy(()=>import('../views/'+path));
  return (
    <Suspense fallback={<>加载中。。。</>}>
      <Comp/>
    </Suspense>
  )
}

2.3 重定向封装

src/components/Redirect.js

import React, { useEffect } from 'react'
import {useNavigate} from 'react-router-dom'

export default function Redirect({to}) {
  const Navigate = useNavigate();
  useEffect(()=>{
    Navigate(to,{replace:true});
  },[]);

  return null;
};

2.4 嵌套路由中的组件Outlet

src/views/Films.js

import React from 'react'
import {Outlet} from 'react-router-dom'
export default function Films() {
  return (
    <div>
      <div style={{height:"200px",background:"pink"}}>轮播</div>
      {/* 这里会呈现 NowPlaying或commingSoon的内容 */}
      <Outlet></Outlet>
    </div>
  )
}

3. 导航跳转

3.2 声明式导航(NavLink标签)

src/components/Tabbar/Tabbar.js

import style from './Tabbar.module.css'
import React from 'react'
import {NavLink} from 'react-router-dom'

export default function Tabbar() {
  return (
    <div>
      <ul>
        <li>
          {/* Link没有高亮className*/}
          {/* <Link to="/films">影院</Link> */}
          <NavLink to="/films" className={({isActive})=>isActive?style.tabActive:''}>电影</NavLink>
        </li>
        <li>
          <NavLink to="/cinemas" className={({isActive})=>isActive?style.tabActive:''}>影院</NavLink>
        </li>
        <li>
          <NavLink to="/center" className={({isActive})=>isActive?style.tabActive:''}>我的</NavLink>
        </li>
      </ul>
    </div>
  )
}

src/components/Tabbar/Tabbar.module.css

.tabActive{
  color: pink;
}

/* 会影响全局,最好加自定义className */
li{
  list-style: none;
}

3.2 编程式导航跳转(useNavigate)

src/views/films/NowPlaying.js

import React,{useState,useEffect} from 'react'
import axios
 from 'axios';
import { useNavigate } from 'react-router-dom';
import FilmItem from '../../components/FilmItem';

export default function NowPlaying() {
  const [list,setList] = useState([]);
  useEffect(()=>{
    //异步获取数据
    axios({
      url:"https://m.maizuo.com/gateway?cityId=110100&pageNum=1&pageSize=10&type=1&k=9261499",
      method:'get',
      headers:{
        'X-Client-Info': '{"a":"3000","ch":"1002","v":"5.2.1","e":"16745641013679850669801473","bc":"110100"}',
        'X-Host': 'mall.film-ticket.film.list'
      }
    }).then(res=>{
      setList(res.data.data.films)
    })
  },[])

  // const navigate = useNavigate();
  // const handleChangePage = id => {
  //   //query-url传参 
  //   // navigate(`/detail?id=${id}&type=2`)

  //   //路由传参
  //   navigate(`/detail/${id}/2`)
  // }
  return (
    <div>
      {
        list.map(item=>{
          return (
            // <div key={item.filmId} onClick={() => handleChangePage(item.filmId)}>{item.name}</div>
            
            <FilmItem key={item.filmId} {...item} />
          )
        })
      }
    </div>
  )
}

3.2.1 获取参数(url地址都会保存参数,刷新不会丢失)

3.2.1.1 useSearchParams

src/views/Details-searchParams.js

<Route path="/detail" element={<Detail/>} />
navigate(`/detail?id=${id}&type=2`)

import React from 'react'
import { useSearchParams } from 'react-router-dom'

export default function Details() {
  const [searchParmas,setSearchParmas] = useSearchParams();
  console.log(searchParmas.get('id'))//获取参数
  console.log(searchParmas.has('name'))//判断是否有参数
  return (
    <div>
      Details
      <button onClick={()=>{
        // 不能单独修改单个parmas
        setSearchParmas({id:1000,type:1})//修改参数
      }}>猜你喜欢</button>
    </div>
  )
}
3.2.1.1 useParams

src/views/Details-params.js

<Route path="/detail/:id/:type" element={<Detail/>} />
navigate(`/detail/${id}/2`)

import React from 'react'
import { useNavigate, useParams } from 'react-router-dom'

export default function Details() {
  const params = useParams();
  const navigate = useNavigate();
  console.log(params.id)//获取参数
  return (
    <div>
      Details
      <button onClick={()=>{
        navigate('/detail/1000/3')
      }}>猜你喜欢</button>
    </div>
  )
}

4. Login.js

import React from 'react'
import { useNavigate } from 'react-router-dom';

export default function Login() {
  const navigate = useNavigate();

  return (
    <div>
      <h1>登录页面</h1>
        <input type="text" />
        <button onClick={()=>{
          localStorage.setItem('token',"xxx");
          navigate('/center')
        }}>登录</button>
    </div>
  )
}

5. 自定义封装withRouter

import React from 'react'
import { useLocation, useNavigate, useParams } from 'react-router-dom'

export default function withRouter(Component) {
  return function(props){
    const navigate = useNavigate();
    const params = useParams();
    const location = useLocation();
    return <Component {...props} history={{navigate,params,location}}/>
  }
}
import React from 'react'
import withRouter from './withRouter'

function FilmItem(props) {
  const handleChangePage = id => {
    props.history.navigate(`/detail/${id}/type=2`)//跳转页面
    console.log(props.history.params)//获取参数对象
    console.log(props.history.location)//获取当前路由
  }
  return (
    <div>
      <li onClick={() => handleChangePage(props.filmId)}>{props.name}</li>
    </div>
  )

  
}

export default withRouter(FilmItem) 

6. useNavigate()替换history.goBack()和goForward()

import React from 'react'
import {useNavigate} from 'react-router-dom'

export default function App() {
    const navigate = useNavigate()
    return (
        <div>
            <button onClick={() => navigate(-2)}>Go 2 pages back</button>
      		<button onClick={() => navigate(-1)}>Go back</button>
      		<button onClick={() => navigate(1)}>Go forward</button>
      		<button onClick={() => navigate(2)}>Go 2 pages forward</button>
        </div>
    )
}

7. 从后端获取路由

import React, { lazy, Suspense, useEffect, useState } from 'react'
import {useRoutes} from 'react-router-dom'
import Redirect from '../components/Redirect'
import axios from 'axios';
const LocalRouterMap = {
  "/home": 'NewsSandBox/Home/Home',
  "/user-manage/list": 'NewsSandBox/user-manage/UserList',
  "/right-manage/role/list": 'NewsSandBox/Right-manage/RoleList',
  "/right-manage/right/list": 'NewsSandBox/Right-manage/RightList',
  "/news-manage/add": 'NewsSandBox/news-manage/NewsAdd',
  "/news-manage/draft": 'NewsSandBox/news-manage/NewsDraft',
  "/news-manage/category": 'NewsSandBox/news-manage/NewsCategory',
  "/news-manage/preview/:id": 'NewsSandBox/news-manage/NewsPreview',
  "/news-manage/update/:id": 'NewsSandBox/news-manage/NewsUpdate',
  "/audit-manage/audit": 'NewsSandBox/audit-manage/Audit',
  "/audit-manage/list": 'NewsSandBox/audit-manage/AuditList',
  "/publish-manage/unpublished": 'NewsSandBox/publish-manage/Unpublished',
  "/publish-manage/published": 'NewsSandBox/publish-manage/Published',
  "/publish-manage/sunset": 'NewsSandBox/publish-manage/Sunset',
};


export default function IndexRouter() {
  const [element,setElement] = useState([]);

  useEffect(()=>{
    let NewsRouter = [];
    Promise.all([axios.get("/rights"), axios.get("/children")]).then((res) => {
      let backRouteList = [...res[0].data, ...res[1].data];
      backRouteList.forEach(item=>{
        //有页面权限和角色人员权限
        if(LocalRouterMap[item.key] && (item.pagepermisson || item.routepermisson)){
          NewsRouter.push(
            {
              path:item.key,
              element: LazyLoad(LocalRouterMap[item.key])
            }
          )
        }
      });

      let hasNPRoute = NewsRouter.length > 0 ? [{path:'*',element:LazyLoad('NewsSandBox/Nopermission/Nopermission')}]:[];
      setElement(
        [
          {
            path:'/login',
            element:LazyLoad('Login/Login'),
          },
          {
            path:'/news',
            element:LazyLoad('News/News'),
          },
          {
            path:'/detail/:id',
            element:LazyLoad('News/Detail'),
          },
          {
            path:'/',
            element:<AuthCom>{LazyLoad('NewsSandBox/NewsSandBox')}</AuthCom>,
            children:[
              ...NewsRouter,
              {
                path:'',
                element:<Redirect to="/home" />,
              },
              ...hasNPRoute
            ]
          }, 
          {
            path:'/TestAsyncRedux',
            element:LazyLoad('Test-AsyncRedux')
          },
          {
            path:'/TestCreateAsyncThunk',
            element:LazyLoad('Test-CreateAsyncThunk')
          },
          {
            path:'/CreateSelector',
            element:LazyLoad('Test-CreateSelector')
          },
        ]
      );
    });
  },[]);

  const routes = useRoutes(element)
  return (
    routes
  )
}

//路由拦截
function AuthCom({children}){//props.children
  const isLogin = window.localStorage.getItem('token');
  return isLogin?children:<Redirect to="/login"/>
}

//路由懒加载,重定向的不用再调用懒加载函数
const LazyLoad = path => {
  const Comp = lazy(()=>import('../views/'+path));
  return (
    <Suspense fallback={<>加载中。。。</>}>
      <Comp/>
    </Suspense>
  )
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值