npm install react-router-dom
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
export default function App() {
return (
<Router>
<div>
<nav>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
<li>
<Link to="/users">Users</Link>
</li>
</ul>
</nav>
{/* A <Switch> looks through its children <Route>s and
renders the first one that matches the current URL. */}
<Switch>
<Route path="/about">
<About />
</Route>
<Route path="/users">
<Users />
</Route>
<Route path="/">
<Home />
</Route>
</Switch>
</div>
</Router>
);
}
import React from "react";
import ReactDOM from "react-dom";
import {
BrowserRouter as Router,
Switch,
Route
} from "react-router-dom";
function App() {
return (
<div>
<Switch>
{/* If the current URL is /about, this route is rendered
while the rest are ignored */}
<Route path="/about">
<About />
</Route>
{/* Note how these two routes are ordered. The more specific
path="/contact/:id" comes before path="/contact" so that
route will render when viewing an individual contact */}
<Route path="/contact/:id">
<Contact />
</Route>
<Route path="/contact">
<AllContacts />
</Route>
{/* If none of the previous routes render anything,
this route acts as a fallback.
Important: A route with path="/" will *always* match
the URL because all URLs begin with a /. So that's
why we put this one last of all */}
<Route path="/">
<Home />
</Route>
</Switch>
</div>
);
}
ReactDOM.render(
<Router>
<App />
</Router>,
document.getElementById("root")
);
switch标签的作用:
当匹配到的路径有相同时,只匹配第一个,避免组件重复渲染。
link 和 navLink
React Router provides a <Link>
component to create links in your application. Wherever you render a <Link>
, an anchor (<a>
) will be rendered in your HTML document.
<Link to="/">Home</Link>
// <a href="/">Home</a>
The <NavLink>
is a special type of <Link>
that can style itself as “active” when its to
prop matches the current location.
<NavLink to="/react" activeClassName="hurray">
React
</NavLink>
// When the URL is /react, this renders:
// <a href="/react" className="hurray">React</a>
// When it's something else:
// <a href="/react">React</a>
Any time that you want to force navigation, you can render a <Redirect>
. When a <Redirect>
renders, it will navigate using its to
prop.
<Redirect to="/login" />
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link,
useParams,
useRouteMatch
} from "react-router-dom";
// Since routes are regular React components, they
// may be rendered anywhere in the app, including in
// child elements.
//
// This helps when it's time to code-split your app
// into multiple bundles because code-splitting a
// React Router app is the same as code-splitting
// any other React app.
export default function NestingExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/topics">Topics</Link>
</li>
</ul>
<hr />
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/topics">
<Topics />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return (
<div>
<h2>Home</h2>
</div>
);
}
function Topics() {
// The `path` lets us build <Route> paths that are
// relative to the parent route, while the `url` lets
// us build relative links.
let { path, url } = useRouteMatch();
return (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${url}/rendering`}>Rendering with React</Link>
</li>
<li>
<Link to={`${url}/components`}>Components</Link>
</li>
<li>
<Link to={`${url}/props-v-state`}>Props v. State</Link>
</li>
</ul>
<Switch>
<Route exact path={path}>
<h3>Please select a topic.</h3>
</Route>
<Route path={`${path}/:topicId`}>
<Topic />
</Route>
</Switch>
</div>
);
}
function Topic() {
// The <Route> that rendered this component has a
// path of `/topics/:topicId`. The `:topicId` portion
// of the URL indicates a placeholder that we can
// get from `useParams()`.
let { topicId } = useParams();
let { path, url, params, isExact } = useRouteMatch();
console.log(path); //
console.log(url);
console.log(params); //
console.log(isExact);
return (
<div>
<h3>{topicId}</h3>
</div>
);
}
useParams():获取路由参数
useRouteMatch():获取match对象,包括path,url,params,isExact。
以上面代码为例,打印的path,url,params,isExact分别为:
path:/topics/:topicId
url:/topics/rendering
params:{topicId: "rendering"}
isExact:true
import React from "react";
import {
BrowserRouter as Router,
Route,
Link,
Switch,
Redirect,
useLocation
} from "react-router-dom";
export default function NoMatchExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/old-match">Old Match, to be redirected</Link>
</li>
<li>
<Link to="/will-match">Will Match</Link>
</li>
<li>
<Link to="/will-not-match">Will Not Match</Link>
</li>
<li>
<Link to="/also/will/not/match">Also Will Not Match</Link>
</li>
</ul>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/old-match">
<Redirect to="/will-match" />
</Route>
<Route path="/will-match">
<WillMatch />
</Route>
<Route path="*">
<NoMatch />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return <h3>Home</h3>;
}
function WillMatch() {
return <h3>Matched!</h3>;
}
function NoMatch() {
let location = useLocation();
console.log(location)
return (
<div>
<h3>
No match for <code>{location.pathname}</code>
</h3>
</div>
);
}
useLoaction()可以得到:
pathName:"/also/will/not/match",
search: "",
hash: "",
state: undefined,
key: "uaopwy"
具体代表什么含义,需要在项目中体验。
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
// Each logical "route" has two components, one for
// the sidebar and one for the main area. We want to
// render both of them in different places when the
// path matches the current URL.
// We are going to use this route config in 2
// spots: once for the sidebar and once in the main
// content section. All routes are in the same
// order they would appear in a <Switch>.
const routes = [
{
path: "/",
exact: true,
sidebar: () => <div>home!</div>,
main: () => <h2>Home</h2>
},
{
path: "/bubblegum",
sidebar: () => <div>bubblegum!</div>,
main: () => <h2>Bubblegum</h2>
},
{
path: "/shoelaces",
sidebar: () => <div>shoelaces!</div>,
main: () => <h2>Shoelaces</h2>
}
];
export default function SidebarExample() {
return (
<Router>
<div style={{ display: "flex" }}>
<div
style={{
padding: "10px",
width: "40%",
background: "#f0f0f0"
}}
>
<ul style={{ listStyleType: "none", padding: 0 }}>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/bubblegum">Bubblegum</Link>
</li>
<li>
<Link to="/shoelaces">Shoelaces</Link>
</li>
</ul>
<Switch>
{routes.map((route, index) => (
// You can render a <Route> in as many places
// as you want in your app. It will render along
// with any other <Route>s that also match the URL.
// So, a sidebar or breadcrumbs or anything else
// that requires you to render multiple things
// in multiple places at the same URL is nothing
// more than multiple <Route>s.
<Route
key={index}
path={route.path}
exact={route.exact}
children={<route.sidebar />}
/>
))}
</Switch>
</div>
<div style={{ flex: 1, padding: "10px" }}>
<Switch>
{routes.map((route, index) => (
// Render more <Route>s with the same paths as
// above, but different components this time.
<Route
key={index}
path={route.path}
exact={route.exact}
children={<route.main />}
/>
))}
</Switch>
</div>
</div>
</Router>
);
}
import React from "react";
import {
BrowserRouter as Router,
Switch,
Route,
Link
} from "react-router-dom";
// Some folks find value in a centralized route config.
// A route config is just data. React is great at mapping
// data into components, and <Route> is a component.
// Our route config is just an array of logical "routes"
// with `path` and `component` props, ordered the same
// way you'd do inside a `<Switch>`.
const routes = [
{
path: "/sandwiches",
component: Sandwiches
},
{
path: "/tacos",
component: Tacos,
routes: [
{
path: "/tacos/bus",
component: Bus
},
{
path: "/tacos/cart",
component: Cart
}
]
}
];
export default function RouteConfigExample() {
return (
<Router>
<div>
<ul>
<li>
<Link to="/tacos">Tacos</Link>
</li>
<li>
<Link to="/sandwiches">Sandwiches</Link>
</li>
</ul>
<Switch>
{routes.map((route, i) => (
<RouteWithSubRoutes key={i} {...route} />
))}
</Switch>
</div>
</Router>
);
}
// A special wrapper for <Route> that knows how to
// handle "sub"-routes by passing them in a `routes`
// prop to the component it renders.
function RouteWithSubRoutes(route) {
return (
<Route
path={route.path}
render={props => (
// pass the sub-routes down to keep nesting
<route.component {...props} routes={route.routes} />
)}
/>
);
}
function Sandwiches() {
return <h2>Sandwiches</h2>;
}
function Tacos({ routes }) {
return (
<div>
<h2>Tacos</h2>
<ul>
<li>
<Link to="/tacos/bus">Bus</Link>
</li>
<li>
<Link to="/tacos/cart">Cart</Link>
</li>
</ul>
<Switch>
{routes.map((route, i) => (
<RouteWithSubRoutes key={i} {...route} />
))}
</Switch>
</div>
);
}
function Bus() {
return <h3>Bus</h3>;
}
function Cart() {
return <h3>Cart</h3>;
}
import React from "react";
import {
BrowserRouter as Router,
Link,
useLocation
} from "react-router-dom";
// React Router does not have any opinions about
// how you should parse URL query strings.
//
// If you use simple key=value query strings and
// you do not need to support IE 11, you can use
// the browser's built-in URLSearchParams API.
//
// If your query strings contain array or object
// syntax, you'll probably need to bring your own
// query parsing function.
export default function QueryParamsExample() {
return (
<Router>
<QueryParamsDemo />
</Router>
);
}
// A custom hook that builds on useLocation to parse
// the query string for you.
function useQuery() {
return new URLSearchParams(useLocation().search);
}
function QueryParamsDemo() {
let query = useQuery();
return (
<div>
<div>
<h2>Accounts</h2>
<ul>
<li>
<Link to="/account?name=netflix">Netflix</Link>
</li>
<li>
<Link to="/account?name=zillow-group">Zillow Group</Link>
</li>
<li>
<Link to="/account?name=yahoo">Yahoo</Link>
</li>
<li>
<Link to="/account?name=modus-create">Modus Create</Link>
</li>
</ul>
<Child name={query.get("name")} />
</div>
</div>
);
}
function Child({ name }) {
return (
<div>
{name ? (
<h3>
The <code>name</code> in the query string is "{name}
"
</h3>
) : (
<h3>There is no name in the query string</h3>
)}
</div>
);
}
在出现router hook之前,url的传参获取方式如下:
...
<Route exact path="/detail/:id" component={Detail}/>
...
...
componentDidMount() {
console.log(this.props.match.params);
}
...
在地址栏输入“http://localhost:3000/#/detail/3”,打开控制台:
可以看到传过去的id=3已经被获取到了。react-router-dom就是通过“/:”去匹配url传递的参数。
隐式传参
此外还可以通过push函数隐式传参。
修改home.js代码如下:
import React from 'react';
export default class Home extends React.Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<a href='#/detail/3'>去detail</a>
<button onClick={() => this.props.history.push({
pathname: '/detail',
state: {
id: 3
}
})}>通过函数跳转</button>
</div>
)
}
}
在detail.js中,就可以使用this.props.history.location.state获取home传过来的参数:
componentDidMount() {
//console.log(this.props.match.params);
console.log(this.props.history.location.state);
}
跳转后打开控制台可以看到参数被打印:
withRouter用法:
withRouter
,它可以将路由信息更新结果(match、history、location)传给它所包裹的组件,组件相当于是一个<Route>
组件了。使用 withRouter 集成 Redux 和 React router 的方法是:withRouter( connect( mapStateToProps, mapDispatchToProps ...))( wrappedComponent) )
,这样被包裹组件既可以拿到 Redux 的 store (通过 dispatch 和 state),也可以拿到 React router 封装的 match、location、history 等路由信息,于是可以将路由信息与 redux store 集成,将路由信息同步到 store,或从 store 实时获取 路由信息。
注意 ! ! :
需要注意:withRouter 只是用来处理数据更新问题的。在使用一些 redux 的connect()
或者 mobx的inject()
的组件中,如果依赖于路由的更新要重新渲染,会出现路由更新了但是组件没有重新渲染的情况。这是因为 redux 和 mobx 的这些连接方法会修改组件的shouldComponentUpdate
。
所以在使用 withRouter 解决更新问题的时候,一定要保证 withRouter 在最外层,比如withRouter(connect()(Component))
,而不是 connect()(withRouter(Component))