React路由

React 路由是构建单页应用(SPA)时管理页面导航和视图切换的核心工具。

什么是单页面应用?

SPA:单页Web应用(single page web application,SPA),就是只有一张Web页面的应用,是加载单个HTML 页面并在用户与应用程序交互时动态更新该页面的Web应用程序。

优点:
具有桌面应用的即时性、网站的可移植性和可访问性
用户体验好、快,内容的改变不需要重新加载整个页面,局部刷新
缺点:
不利于SEO优化
首次渲染速度慢

为什么需要路由?

单页应用(SPA)中通过 URL 映射不同组件,实现无刷新页面切换。
保持浏览器历史记录同步(前进/后退)。
支持动态路由、嵌套路由、权限控制等场景。

基础用法

路由配置
// App.jsx
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Home from './Home';
import About from './About';
import User from './User';

function App() {
  return (
    <Router>
      <Routes>
        <Route path="/" element={<Home />} />
        <Route path="/about" element={<About />} />
        <Route path="/user/:id" element={<User />} />
        <Route path="*" element={<NotFound />} /> {/* 404 页面 */}
      </Routes>
    </Router>
  );
}
导航组件

<Link>:替代 <a> 标签,无刷新跳转

import { Link } from 'react-router-dom';
<Link to="/about">关于我们</Link>

<NavLink>:高亮当前活动链接 

<NavLink to="/" style={({ isActive }) => ({ color: isActive ? 'red' : 'black' })}>
  首页
</NavLink>
编程式导航
import {useNavigate} from 'react-router-dom'
function LoginButton() {
  const navigate = useNavigate();
  return (
    <button onClick={() => navigate('/about')}>
      登录后跳转
    </button>
  );
}
//navigate(跳转的路径,携带参数的对象) params和search参数直接拼接路径后,state传参需要对象
navigate('detail',{replace:false,state:{id:xxx,message:xxxx})
navigate(1)前进1 navigate(-1)后退1

路由v5版本与v6版本对比

1.routes代替了switch,Navigate替代了Redirect,element替代了component
2.不用Route标签包裹子组件,可以直接使用element属性,并且不需要exact来表示精准匹配,V6版本内部算法改变,它默认就是匹配完整路径,先后顺序不再重要,它能够自动找出最优匹配路径

//v5版本
<NavLink activeClassName='xxxxx' to='/home'>xxx</NavLink>
 <switch>
    <Route path='/' component={Home}/>
    <Route path='/home' component={Home}/> 
    <Route path='/about' component={About}/>
    <Route  component={NotFound}/>
 </switch>

//v6版本
<NavLink className={({isActive})=>isActive?'xxx':''} to='/home'>xxx</NavLink>
 <Routes>
    <Route path='/' element={<Navigate to='/home'  replace={false}/>}/>//replace控制跳转模式,push或者 
    replace,默认push
    <Route path='/home' element={<Home/>} caseSensitive={false}/> //caseSensitive路由匹配区分大小写, 
    默认false
   <Route path='/about' element={<About/>}>  //嵌套路由
        <Route path='/about/news' element={<News/>}/>
        <Route path='/about/message' element={<Message/>}/>
   </Route>
 </Routes>

 函数组件路由表

//函数组件里 单独维护一个routes的文件夹,方便路由的扩展
export default [
    {path:'/',element:<Navigate to='/home' />},
    {
        path:'/home',
        element:<Home/>
    },
    {
        path:'/about',
        element:<About/>,
        children:   //嵌套子路由
          [
            {path:'news',element:<News/>},
            {path:'message',element:<Message/>}
         ]
    },
]

import {Link,NavLink,useRoutes} from 'react-router-dom'
export default function App() {
  const element= useRoutes(router)  //router引入的路由链表
  return (
    <div>
      <div>
      <Link to='/home'>Home</Link> | 
      <Link to='/about'>About</Link>
      </div>
      <div>
        {element}
      </div>
       
    </div>
  )
}

子路由占位符Outlet

//v6版本使用 Outlet组件,此组件是一个占位符,告诉 React Router嵌套的内容应该放到哪里
//子路由匹配路径问题这几种写法等价
   //<NavLink to='news'>news</NavLink>
  //<NavLink to='./news'>news</NavLink>
  //<NavLink to='/about/news'>news</NavLink>

// 父路由
<Route path="/about" element={<About/>}>
  {/* 子路由路径会拼接父路径 */}
  <Route path="news" element={<News/>} />
  <Route index element={<NewsHome/>} /> {/* 默认子路由 */}
</Route>

import { NavLink,Outlet } from 'react-router-dom'
export default class About extends Component {
  render() {
    return (
        <div>
           About组件
           <div> 
              <NavLink to='news'>news</NavLink> | <NavLink to='message'>message</NavLink> 
            </div>
            <div>
            <Outlet/>
            </div>
        </div>
    )
  }
}

路由传参

params传参

路径参数/user/:id → useParams()

//路由表
  {
        path:'/about',
        element:<About/>,
        children:
          [
            {path:'/about/news',element:<News/>},
            {path:'/about/message',element:<Message/>, children:
            [{path:'detail/:id/:message',element:<Detail/>}]
            }
        ]
   },

export default class news extends Component {
    state={
        arrList:[{id:1,message:'message1'},
                 {id:2,message:'message2'},
                 {id:3,message:'message3'}]
    }
  render() {
    return (
        <div>
            <ul>
              {this.state.arrList.map(item=>(
               <li key={item.id}>
                <Link to={`detail/${item.id}/${item.message}`}>{item.message}</Link>               
              </li>
              ))}
          </ul>
          <div>
            <Outlet/>
          </div>
       </div>
    )
  }
}

//useMatch也可以拿到params参数  写法 useMatch('/About/messagedetail/:id/:message/')参数是完整路径
import React from 'react'
import {useParams} from 'react-router-dom'//useParams拿到传递值得对象
export default function detail() {
   const {id,message}= useParams()
  return (
    <ul>
        <li>message编号为:{id}</li>
        <li>message信息为:{message}</li>  
    </ul>
  )
}

查询参数/search?q=react → useSearchParams()

//路由表
  {
        path:'/about',
        element:<About/>,
        children:
          [
            {path:'/about/news',element:<News/>},
            {path:'/about/message',element:<Message/>, children:
            [{path:'detail',element:<Detail/>}]
            }
        ]
   }

export default class news extends Component {
    state={
        arrList:[{id:1,message:'message1'},
                 {id:2,message:'message2'},
                 {id:3,message:'message3'}]
    }
  render() {
    return (
        <div>
            <ul>
              {this.state.arrList.map(item=>(
               <li key={item.id}>
                <Link to={`detail?id=${item.id}&message=${item.message}`}>{item.message}</Link>               
              </li>
              ))}
          </ul>
          <div>
            <Outlet/>
          </div>
       </div>
    )
  }
}

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

export default function detail() {
   const [search,setSearch]= useSearchParams();
 //要获取值search.get('id') ,setSearch改为对应的传参,例如setSearch('id=4&message=嘻嘻')
 const id=search.get('id');
 const message=search.get('message')
  return (
    <ul>
        <li>message编号为:{id}</li>
        <li>message信息为:{message}</li>  
    </ul>
  )
}

state传参

状态传递navigate('/detail', { state: { data } }) → useLocation().state

//路由表
  {
        path:'/about',
        element:<About/>,
        children:
          [
            {path:'/about/news',element:<News/>},
            {path:'/about/message',element:<Message/>, children:
            [{path:'detail',element:<Detail/>}]
            }
        ]
   }

export default class news extends Component {    
    state={
        arrList:[{id:1,message:'message1'},
                 {id:2,message:'message2'},
                 {id:3,message:'message3'}]
    }
  render() {
    return (
        <div>
            <ul>
              {this.state.arrList.map(item=>(
               <li key={item.id}>
                <Link to='detail' state={{
                    id:item.id,
                    message:item.message
                }}>{item.message}</Link>               
              </li>
              ))}
          </ul>
          <div>
            <Outlet/>
          </div>
       </div>
     
    )
  }
}

import {useLocation} from 'react-router-dom'
export default function detail() {
   const {state:{id,message}}= useLocation(); 
  return (
    <ul>
        <li>message编号为:{id}</li>
        <li>message信息为:{message}</li>  
    </ul>
  )
}

 路由守卫(权限控制) 

// 自定义 ProtectedRoute 组件
function ProtectedRoute({ children }) {
  const isAuthenticated = checkAuth(); // 你的权限验证逻辑
  const navigate = useNavigate();

  useEffect(() => {
    if (!isAuthenticated) {
      navigate('/login');
    }
  }, [isAuthenticated, navigate]);

  return isAuthenticated ? children : null;
}

// 使用方式
<Route
  path="/admin"
  element={
    <ProtectedRoute>
      <AdminPanel />
    </ProtectedRoute>
  }
/>

懒加载路由

import { lazy, Suspense } from 'react';
const LazyComponent = lazy(() => import('./HeavyComponent'));

<Route
  path="/heavy"
  element={
    <Suspense fallback={<div>Loading...</div>}>
      <LazyComponent />
    </Suspense>
  }
/>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值