React —— 路由的使用
Posted 旺仔好吃糖
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了React —— 路由的使用相关的知识,希望对你有一定的参考价值。
🧁个人主页:个人主页
✌支持我 :点赞👍收藏🌼关注🧡
文章目录
⛳React 路由
🔮路由简介
1.什么是路由
📍路由是根据不同的 url 地址显示不同的内容或页面
📍一个针对React而设计的路由解决方案,可以友好的帮助解决React components到URL之间的同步映射关系
2.路由安装
npm install react-router-dom@5
🧩路由的使用
(1)路由方法导入
import React, Component from 'react'
import HashRouter,Route from 'react-router-dom'
(2)定义路由
<HashRouter>
<Route path='/films' component=Films/>
<Route path='/cinemas' component=Cinemas/>
<Route path='/center'component=Center>1111</Route>
</HashRouter>
(3)路由重定向
💧1. 会导航到一个新的位置,新的位置将覆盖历史堆栈中的当前条目,例如服务器端重定向
💧2. 当用户访问某界面时,若该界面并不存在,则需跳转到一个我们自定义的界面,此时需要用Redirect重定向
//引入redirect
import HashRouter,Redirect,Route from 'react-router-dom'
..................................
<Redirect from='/' to="/films"></Redirect>
💧1. from: string => 要从中进行重定向的路径名
💧2. to:string => 要重定向到的位置
以上为模糊匹配,凡是以/开头的都会跳转到films
解决
引入Switch组件
import HashRouter,Redirect,Route,Switch from 'react-router-dom'
....................................
<Switch>
<Route path='/films' component=Films/>
<Route path='/cinemas' component=Cinemas/>
<Route path='/center'component=Center>1
/* 模糊匹配 凡是以/开头的都会跳转到films*/
<Redirect from='/' to="/films"></Redirect>
</Switch>
Switch如switch语句一样,若匹配到,则不在匹配;若均未匹配到,则跳转到自定义的界面films
注意:Redirect必须放在Switch里的最后一行,表示上面路由都匹配不到,则跳转到“/films”组件
精准匹配
//语法
<Redirect from='/' to="/films" exact></Redirect>
加上 exact 表示精确匹配,只有完全是"/“时才会跳转到”/films"界面
............................................
<Switch>
<Route path='/films' component=Films/>
<Route path='/cinemas' component=Cinemas/>
<Route path='/center'component=Center>1111</Route>
/* 模糊匹配 凡是以/开头的都会跳转到films*/
<Redirect from='/' to="/films"></Redirect>
/* 精确匹配 */
<Redirect from='/' to="/films" exact></Redirect>
<Route component=NotFound></Route>
</Switch>
当输入的路径都不匹配时,则会跳转到 NotFound界面
(4)嵌套路由
//films组件中
<Switch>
<Route path='/films/nowplaying' component=nowplaying></Route>
<Route path='/films/Comingsoon' component=Comingsoon></Route>
<Redirect from="/films" to="/films/nowplaying"></Redirect>
</Switch>
(5)路由跳转方式
-
声明式导航
import NavLink from 'react-router-dom' <NavLink to="/films" activeClassName='active'>电影</NavLink> <NavLink to="/cinemas" activeClassName='active'>影院</NavLink> <NavLink to="/center" activeClassName='active'>我的</NavLink>
点击时将会跳转到对应的界面,activeClassName属性每次加到被点击的那个标签上,可以通过这个来添加样式
-
编程式导航(注意HOOK使用 类组件不可以直接使用)
-
第一种写法
//被Route包裹时,组件中会获得形参props this.props.history.push(`/center`)
-
第二种写法
import useHistory from 'react-router-dom' ...................................... const history = useHistory() const handleChangePage=(id)=> history.push(`/detail/$id`)
-
(6)路由传参
-
动态路由传参(推荐)
//定义路由 <Route path='/detail/:myid' component=Detail></Route> //传参 history.push(`/detail/$id`) //获得参数 props.match.params.myid
其中 ":myid"为占位符(要传的参数),表示路由必须写成 =>/detail/111的格式
页面刷新,参数不会丢失
-
query传参
//定义路由 <Route path='/detail' component=Detail></Route> //传参 props.history.push(pathname:'/detail',query:myid:id) //获得参数 console.log(props.location.query.myid,'利用id去后端拿数据');
刷新地址栏,参数丢失
-
state传参
//定义路由 <Route path='/detail' component=Detail></Route> //传参 history.push(pathname:'/detail',state:myid:id) //获得参数 console.log(props.location.state.myid,'利用id去后端拿东西');
使用HashRouter的话,刷新页面,参数会丢失
(7)路由拦截
拦截路由变化做自定义处理,尚未登录时点击观看纪录,则会跳转到登录界面
function isAuth()
return localStorage.getItem("token")
............................................
<Route path='/center' render=()=>
return isAuth()?<Center/>:<Redirect to="/login"></Redirect>
></Route>
判断token,若没有则重定向到“/login”界面
(8)路由模式
HashRouter模式
💧有 # 路径,不像后端发请求要页面
BrowserRouter模式
💧没有 # 的路径,真正向后端发请求要页面,后端没有对对应的路径处理路径,就会404
额外命名
import BrowserRouter as Router,Redirect,Route,Switch from 'react-router-dom'
......................................
<Router></Router>
将BrowserRouter/HashRouter,重新命名为Router,方便切换
(9)withRouter
作用
💧将一个组件包裹在Route里面,然后react-router的三个对象history,location,match就会被放进这个组件的props属性中,此时这个组件就有了props,并具备了路由的属性
应用场景
<Route path='/center' render=()=>
return isAuth()?<Center/>:<Redirect to="/login"></Redirect>
></Route>
//组件使用render函数直接渲染,此时组件的this.props为空,无法执行props中的history,location,match方法
💧在层级关系组件中,无法直接获得父组件的props(除传递props外)或 父组件就没有props,此时子组件就无法具备路由的属性
语法
import React, Component from 'react'
import withRouter from 'react-router-dom'
function Center(props)
return (
<div>
<div onClick=()=>
props.history.push(`/filmsorder`)
>
</div>
</div>
)
export default withRouter(Center)
🏫项目注意
反向代理
前端解决跨域问题
-
在src下创建 setupProxy.js文件
-
安装
npm i http-proxy-middleware
-
setupProxy.js文件中配置反向代理
const createProxyMiddleware = require('http-proxy-middleware'); module.exports = function(app) // app.use(),这个可以配置多个代理 app.use( //ajax是需要转发的请求(所有带有/ajax前缀的请求都会转发给 https://i.maoyan.com) '/ajax', createProxyMiddleware( //配置转发目标地址(能返回数据的服务器地址) target: 'https://i.maoyan.com', changeOrigin: true, ) ); // https://i.maoyan.com/ajax/mostExpected?limit=10&offset=0&token=&optimus_uuid=C43ACD00C40211EDB6FB1DC502B2262A6C9A830AE637431CBD63E72665CE4A70&optimus_risk_level=71&optimus_code=10
注意:每次编写完setupProxy.js文件后,都要 npm start 重启服务器
-
发送请求
axios( url:'/ajax/mostExpected?limit=10&offset=0&token=&optimus_uuid=C43ACD00C40211EDB6FB1DC502B2262A6C9A830AE637431CBD63E72665CE4A70&optimus_risk_level=71&optimus_code=10', method:'get' ).then(res=> console.log(res.data); )
CSSModule
📍避免所有样式全局剩下,造成样式可能被错误覆盖
📍使用CSS Modules后,样式默认局部
📍对于class选择器、id选择器、以及加了class/id的标签选择器有效(.active ul li)
-
将css文件名改为 => Film.module.css
-
引入css文件
import style from './css/Film.module.css'
-
<NavLink to="/films/comingsoon" activeClassName=style.zhangsan> .............................. //css文件中 .zhangsan color:green;
如果想要切换到全局模式
-
定义全局样式
:global(.active) color:yellow;
-
定义多个全局样式
:global .link color:red; .box color:blue;
React 使用 React Hooks 从路由器获取道具
【中文标题】React 使用 React Hooks 从路由器获取道具【英文标题】:React get props from Router with React Hooks 【发布时间】:2019-11-05 02:49:49 【问题描述】:我正在尝试使用 React Hooks
重构我的代码,但我真的不明白如何使用 Hooks 通过 React 路由器将 props 传递给我的组件。
旧的(正常的)React 代码如下所示:
App.js
import React from 'react';
import withRouter from "react-router-dom";
import Routes from './routes/Routes';
function App()
const childProps=something: "else";
return (
<div className="App">
<Routes childProps=childProps />
</div>
);
export default withRouter(App);
Routes.js
import Switch, Route from 'react-router-dom';
import Game from '../game/Game';
import Scenario from '../game/Scenario';
const CustomRoute = ( component: C, props: cProps, ...rest ) =>
<Route
...rest
render=(props) =>
<C ...props ...cProps />
/>;
export const Routes = (childProps) =>
<Switch>
<Route path="/" exact component=Game props=childProps />
<CustomRoute path="/scenario/:id" exact component=Scenario props=childProps/>
</Switch>
Game.js
import React from 'react';
const Game = () =>
return (
<div className="Game">
<header className="Game-header">
<a href="/scenario/0">
START
</a>
</header>
</div>
);
;
export default Game;
Scenario.js
export default class Scenario extends Component
constructor(props)
super(props);
this.state =
scenarios: null,
scenarioId: null,
currentScenario: null
async componentDidMount()
const scenarioId = await this.props.match.params.id;
const scenarios = await data.scenarios;
this.setState(scenarios, scenarioId);
this.getScenario();
getScenario = () =>
this.state.scenarios.forEach((scenario) =>
if (scenario.id === this.state.scenarioId)
const currentScenario = scenario;
this.setState(currentScenario);
)
render()
return (
<div>
this.state.currentScenario != null
? this.state.currentScenario.options.length === 1
? (
<div>
<div>this.state.currentScenario.text</div>
<div>this.state.currentScenario.options[0].text</div>
<a href="/">Go Back</a>
</div>
)
: (
<div>
<div>this.state.currentScenario.text</div>
<div>this.state.currentScenario.options.map((option, index) => (
<div key=index>
<a href=`/scenario/$option.to`>
option.text
</a>
</div>
))</div>
</div>
)
: null
</div>
);
;
所以我在网上找到了这段代码,它会改变我从路由器获取道具的方式:
HookRouter.js
import * as React from 'react';
import BrowserRouter, Route from 'react-router-dom';
const RouterContext = React.createContext(null);
export const HookedBrowserRouter = ( children ) => (
<BrowserRouter>
<Route>
(routeProps) => (
<RouterContext.Provider value=routeProps>
children
</RouterContext.Provider>
)
</Route>
</BrowserRouter>
);
export function useRouter()
return React.useContext(RouterContext);
;
新的 App.js
import React from 'react';
import withRouter from "react-router-dom";
import Routes from './routes/Routes';
import HookedBrowserRouter, useRouter from './routes/HookRouter';
function App()
const childProps=something: "else";
return (
<HookedBrowserRouter>
<div className="App">
<Routes childProps=childProps />
</div>
</HookedBrowserRouter>
);
export default withRouter(App);
我在新的 Scenario.js 中得到了他的帮助
import React, Component, useState, useEffect from 'react';
import data from '../data/fake';
import useRouter from '../routes/HookRouter';
const RouterContext = React.createContext(null);
const HookSceneario = () =>
const [scenarios, setScenarios] = useState(null);
const [scenarioId, setScenarioId] = useState(null);
const [currentScenario, setCurrentScenario] = useState(null);
// Similar to componentDidMount and componentDidUpdate:
// Update the document title using the browser API
// console.log(React.useContext(RouterContext));
useEffect(() =>
console.log(scenarios);
);
return (
<div>
// ...
</div>
);
所以useState
替换了类构造函数中的this.state
,useEffect
应该替换componentDidMount
,但我找不到从路由器获取props
的方法。
【问题讨论】:
<Scenario/>
的孩子是否需要 routeProps
?因为你这样做的方式,因为场景是由<Route>
组件呈现的,而你在render=(routeProps) => <C ...routeProps)/>
中传递routeProps
。请注意,我已重命名为routeProps
,以明确render
道具中可用的props
对象是routeProps
(匹配、位置和历史记录)。因此<Scenario/>
已经可以访问routeProps
。
感谢@cbdev420 的建议。所以你是写那段代码的人。我的问题是如何将Scenario
中的这些道具称为带有 Hooks 的函数。看来我不能 console.log
任何道具,比如类。
我认为异步生命周期方法是个坏主意...我可以制作单独的异步函数并将这个逻辑移到那里。然后你在 componentdidmount 中调用这个函数,比如 getScenario
@Bonjov 谢谢你的建议。除非我误解了您的评论,否则上面的代码似乎符合您的建议:在 componentDidMount 中调用异步函数。
【参考方案1】:
我认为这很好地说明了您正在尝试做的事情:
记住:
<Route>
渲染的组件始终可以访问routeProps
(匹配、位置和历史记录)。
如果它是由 component
属性渲染的,就像在 <Route ... component=Home/>
中一样,这是自动的。
如果它是由render
属性渲染的,则需要传播它们,如:
// You can spread routeProps to make them available to your rendered Component
const FadingRoute = ( component: Component, ...rest ) => (
<Route ...rest render=routeProps => (
<FadeIn>
<Component ...routeProps/>
</FadeIn>
)/>
)
Link on CodeSandbox
结果:
完整代码:
index.js
import React from "react";
import ReactDOM from "react-dom";
import BrowserRouter as Router from "react-router-dom";
import AllRoutes from "./AllRoutes";
function App()
return (
<Router>
<AllRoutes />
</Router>
);
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
AllRoutes.js
import React from "react";
import Switch, Route from "react-router-dom";
import Home from "./Home";
import Component1 from "./Component1";
function AllRoutes()
return (
<Switch>
<Route exact path="/" component=Home />
<Route exact path="/comp1" component=Component1 />
</Switch>
);
export default AllRoutes;
Home.js
import React from "react";
import Link from "react-router-dom";
function Home(props)
return (
<div>
I am HOME component
<ul>
<li>
<Link to="/comp1">Component1</Link>
</li>
</ul>
I have access to routeProps: YES
<br />
Because I'm directly rendered from a Route
<ul>
<li>"props.match:" + props.match.toString()</li>
<li>"props.location:" + props.location.toString()</li>
<li>"props.history:" + props.history.toString()</li>
</ul>
</div>
);
export default Home;
Component1.js
import React from "react";
import Link from "react-router-dom";
import Component1Child from "./Component1Child";
import RouterContext from "./RouterContext";
function Component1(props)
const routeProps =
match: props.match,
history: props.history,
location: props.location
;
return (
<RouterContext.Provider value=routeProps>
<div>
<b>I am Component1</b>
<ul>
<li>
<Link to="/">Home</Link>
</li>
</ul>
I have access to routeProps: YES
<br />
Because I'm directly rendered from a Route.
<br />
And I automatically 'inherit' them when I'm rendered through the Route
'component' prop
<ul>
<li>"props.match:" + props.match.toString()</li>
<li>"props.location:" + props.location.toString()</li>
<li>"props.history:" + props.history.toString()</li>
</ul>
<Component1Child />
</div>
</RouterContext.Provider>
);
export default Component1;
Component1Child.js
import React from "react";
import Component1GrandChild from "./Component1GrandChild";
function Component1Child(props)
return (
<div>
<b>I am Component1Child</b> <br />
<br />
I have access to routeProps: NO
<br />
Because I'm NOT directly rendered from a Route.
<br />I am rendered by Componen1 and routeProps are not automatically
passed down.
<ul>
<li>"props.match:" + props.match</li>
<li>"props.location:" + props.location</li>
<li>"props.history:" + props.history</li>
</ul>
<Component1GrandChild />
</div>
);
export default Component1Child;
Component1GrandChild.js
import React from "react";
import useRouteProps from "./useRouteProps";
function Component1GrandChild(props)
const [match, location, history] = useRouteProps();
return (
<div>
<b>I am Component1GrandChild</b> <br />
<br />
I have access to routeProps: YES
<br />
Because I'm consuming the routeProps provided by Component1 (which is the
one directly rendered by the Route)
<br /> And I'm consuming that through a custom hook called useRouteProps.
<br />I am rendered by Componen1 and routeProps are not automatically
passed down.
<ul>
<li>"props.match:" + match</li>
<li>"props.location:" + location</li>
<li>"props.history:" + history</li>
</ul>
</div>
);
export default Component1GrandChild;
RouterContext.js
import React from "react";
const RouterContext = React.createContext(null);
export default RouterContext;
使用RouteProps.js
import useContext from "react";
import RouterContext from "./RouterContext";
function useRouteProps()
const routeProps = useContext(RouterContext);
return [routeProps.match, routeProps.location, routeProps.history];
export default useRouteProps;
【讨论】:
非常感谢您的详细回答。请让我实现您的代码并回复您(标记为正确)。以上是关于React —— 路由的使用的主要内容,如果未能解决你的问题,请参考以下文章
来自 react-route-dom 的 React.js 路由问题
express.js 和 react.js cookie 保存到浏览器但不工作?