React全家桶-react-router原理实现

本教程深入探讨React全家桶的使用,包括React Router的高级特性,如动态路由、懒加载、路由守卫及404页面配置。通过实例讲解如何创建加强版Route组件,实现条件渲染和重定向。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

29.9React课程

第05节:react全家桶

(第5节:react全家桶&)

第5节:react全家桶&

App.js

exact精确匹配,可以使用switch独占如果有一个匹配不会继续往下走,一般要与exact配合使用,否则下面不会执行

fallback返回任意jsx语法,增加动态引入与懒加载实现

import React, { Suspense, lazy } from "react";
import logo from "./logo.svg";
import "./App.css";

import {
  BrowserRouter as Router,
  HashRouter,
  Route,
  Link,
  Switch,
  Redirect
} from "react-router-dom";
import ListTest from "./Pages/ListTest";
// import DetailTest from "./Pages/DetailTest";

const DetailTest = lazy(() => import("./Pages/DetailTest"));

function Index(props) {
  console.log(props);
  return <h2>首页</h2>;
}
function Nav({ history, location }) {
  console.log(history, location);
  return <h2>导航</h2>;
}
function Test404() {
  return <h2>404</h2>;
}

//实现加强版本的route

function UpRoute({ component: Component, isLogin, ...rest }) {
  return (
    <Route
      {...rest}
      render={props => {
        return isLogin ? (
          <Component {...props} />
        ) : (
          <Redirect to={{ pathname: "/login" }} />
        );
      }}
    ></Route>
  );
}

function Login() {
  return <h2>Login</h2>;
}

function Test(props) {
  console.log(props);

  return (
    <div>
      <h2>守卫内容</h2>
    </div>
  );

  // return <div>

  //   {
  //     props.isLogin ? Component : <Redirect to={{pathname:"/login"}}/>
  //   }
  // </div>  ;
}

function App() {
  return (
    <Router>
      <div className="App">
        <h1>React-router</h1>
        <ul>
          <li>
            <Link to="/">首页</Link>
          </li>
          <li>
            <Link to="/nav">菜单1</Link>
          </li>
          <li>
            <Link to="/list">列表</Link>
          </li>
          <li>
            <Link to="/detail/10001">详情</Link>
          </li>
          <li>
            <Link to="/test">守卫测试</Link>
          </li>
        </ul>
      </div>
      <div>
        {/* 路由配置 */}
        <Switch>
          {/* 首页 /nav */}
          {/* switch 一般都会和exact属性配合使用 */}
          <Route exact path="/" component={Index}></Route>
          <Route exact path="/nav" component={Nav}></Route>
          {/* 完全匹配 */}
          {/* /list */}
          {/* /list/react */}
          {/* /list/vue */}
          {/* /list/node */}
          <Route path="/list" component={ListTest}></Route>
          <Route exact path="/detail/:id" component={DetailTest}></Route>
          <UpRoute path="/test" component={Test} isLogin={false}></UpRoute>
          <Route exact path="/login" component={Login}></Route>
          <Route component={Test404}></Route>
        </Switch>
        {/* <Suspense fallback={<div>Loading....</div>}>
          <Route exact path="/detail/:id" component={DetailTest}></Route>{" "}
        </Suspense> */}
      </div>
    </Router>
  );
}

export default App;

history是h5对象的api

import React, { Component } from "react";

function DetailTest({ history, location, match }) {
  console.log(match, location);
  return <h2>宝贝ID:{match.params.id}</h2>;
}

export default DetailTest;
import React, { Component } from "react";

import { Link, Route } from "react-router-dom";

function ReactPage() {
  return <h2>ReactPage</h2>;
}
function VuePage() {
  return <h2>VuePage</h2>;
}
function NodePage() {
  return <h2>NodePage</h2>;
}

function ListTest() {
  return (
    <div>
      <h2>ListTest</h2>
      <ul>
        <li>
          <Link to="/list/react">React</Link>
        </li>
        <li>
          <Link to="/list/vue/">vue</Link>
        </li>
        <li>
          <Link to="/list/node/">node</Link>
        </li>
      </ul>
      <div style={{ border: "1px red solid" }}>
        <Route exact path="/list/react" component={ReactPage}></Route>
        <Route exact path="/list/vue/" component={VuePage}></Route>
        <Route exact path="/list/node/" component={NodePage}></Route>
      </div>
    </div>
  );
}

export default ListTest;

动态路由要完全匹配,点击list进入ListTest去匹配,去加载子路由

有子路由并且是动态匹配,不能对一级路由设置exact

(404页面&)

404页面&

没有任何url匹配输出404,采用漏斗策略

(路由守卫&)

路由守卫&

...rest其他加强属性,小写component jsx不会当做一个组件,要重新起别名

重定向跳转回退不了,其他跳转可以回退。

import React, { Suspense, lazy } from "react";
import logo from "./logo.svg";
import "./App.css";

import {
  BrowserRouter as Router,
  HashRouter,
  Route,
  Link,
  Switch,
  Redirect
} from "react-router-dom";
import ListTest from "./Pages/ListTest";
// import DetailTest from "./Pages/DetailTest";

const DetailTest = lazy(() => import("./Pages/DetailTest"));

function Index(props) {
  console.log(props);
  return <h2>首页</h2>;
}
function Nav({ history, location }) {
  console.log(history, location);
  return <h2>导航</h2>;
}
function Test404() {
  return <h2>404</h2>;
}

//实现加强版本的route

function UpRoute({ component: Component, isLogin, ...rest }) {
  return (
    <Route
      {...rest}
      render={props => {
        return isLogin ? (
          <Component {...props} />
        ) : (
          <Redirect to={{ pathname: "/login" }} />
        );
      }}
    ></Route>
  );
}

function Login() {
  return <h2>Login</h2>;
}

function Test(props) {
  console.log(props);

  return (
    <div>
      <h2>守卫内容</h2>
    </div>
  );

  // return <div>

  //   {
  //     props.isLogin ? Component : <Redirect to={{pathname:"/login"}}/>
  //   }
  // </div>  ;
}

function App() {
  return (
    <Router>
      <div className="App">
        <h1>React-router</h1>
        <ul>
          <li>
            <Link to="/">首页</Link>
          </li>
          <li>
            <Link to="/nav">菜单1</Link>
          </li>
          <li>
            <Link to="/list">列表</Link>
          </li>
          <li>
            <Link to="/detail/10001">详情</Link>
          </li>
          <li>
            <Link to="/test">守卫测试</Link>
          </li>
        </ul>
      </div>
      <div>
        {/* 路由配置 */}
        <Switch>
          {/* 首页 /nav */}
          {/* switch 一般都会和exact属性配合使用 */}
          <Route exact path="/" component={Index}></Route>
          <Route exact path="/nav" component={Nav}></Route>
          {/* 完全匹配 */}
          {/* /list */}
          {/* /list/react */}
          {/* /list/vue */}
          {/* /list/node */}
          <Route path="/list" component={ListTest}></Route>
          <Route exact path="/detail/:id" component={DetailTest}></Route>
          <UpRoute path="/test" component={Test} isLogin={false}></UpRoute>
          <Route exact path="/login" component={Login}></Route>
          <Route component={Test404}></Route>
        </Switch>
        {/* <Suspense fallback={<div>Loading....</div>}>
          <Route exact path="/detail/:id" component={DetailTest}></Route>{" "}
        </Suspense> */}
      </div>
    </Router>
  );
}

export default App;

通过render可以接收函数组件,给Test属性传递其他的属性

创建PrivateRoute
function PrivateRoute({ component: Component, isLogin,
...rest }) {
 // 单独解构出component和isLogin
 // component为渲染⽬标组件,isLogin通常来⾃Redux
 // rest为传递给Route的属性
 return (
 <Route
 {...rest}
 render={
锦绣课堂-React课程
 props => // props包含match等信息直接传给⽬标组件
 isLogin ? ( // 若登陆渲染⽬标组件
 <Component {...props} />
 ) : ( // 未登录重定向到Login
 <Redirect
 to={{
 pathname: "/login",
 state: { redirect: props.location.pathname
} // 重定向地址
 }}
 />
 )
 }
 />
 );
}
创建Login
function Login({ location, isLogin, login }) {
 const redirect = location.state.redirect || "/"; // 重定向
地址
 if (isLogin) return <Redirect to={redirect} />;
 return (
 <div>
 <p>登录</p>
 <hr />
 <button onClick={login}>登录</button>
 </div>
 );
}
配置路由,ReduxTest
<PrivateRoute path="/management" component={ProductMgt} />
<Route path="/login" component={Login} />
给PrivateRoute传递isLogin={true}试试
整合redux,获取和设置登录态,创建./store/user.js
const initialState = { isLogin: false, loading: false
};
export default (state = initialState, action) => {
 switch (action.type) {
 case "requestLogin":
 return { isLogin: false, loading: true };
 case "loginSuccess":
 return { isLogin: true, loading: false };
 case "loginFailure":
 return { isLogin: false, loading: false };
 default:
 return state;
 }
};
export function login(user) {
 return dispatch => {
 dispatch({ type: "requestLogin" });
 setTimeout(() => {
 dispatch({ type: "loginSuccess" });
 }, 1000);
 };
}

引入,store/index.js

import user from "./user";
const store = createStore(
combineReducers({ user }),
applyMiddleware(logger, thunk)
);
连接状态,ReduxTest.js
import { login } from "./store/user.redux";
const PrivateRoute = connect(state => ({
isLogin: state.user.isLogin
}))(function({ isLogin, ...rest }) {})
const Login = connect(
state => ({
isLogin: state.user.isLogin
}),
{ login }
)(function({ isLogin, login }) {})

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

wespten

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值