这是我参与更文挑战的第9天,活动详情查看: 更文挑战
通过 URL 传递参数
通过 URL 传递参数是很常见的需求,比如显示文章/商品的 ID。 推荐将参数作为路径的一部分(而不是查询参数),这样做对搜索引擎更友好、更有语义。
一、如何通过 URL 传递参数
演示一个传递 articleId 的例子 ?
function App() {
return (
<Router>
<nav>
<ul>
<li>
<Link to="/article/1">aritcle 1</Link>
</li>
<li>
<Link to="/article/2">aritcle 2</Link>
</li>
<li>
<Link to="/article/3">aritcle 3</Link>
</li>
</ul>
</nav>
<div class="page-container">
<Route path="/article/:id" component={Article}></Route>
</div>
</Router>
);
}
复制代码
二、如何获取参数
对于 React Router
render 的组件通过高阶组件的方式,会传递一个 match
的属性,在 match.props
中可以访问到传递的参数。
- Hook –
useParams
,React Router v5.1 新增
import { useParams } from "react-router-dom";
// 注意:这时的组件是被包裹在 <Route> 里
<Route path="/blog/:slug">
<BlogPost />
</Route>;
function BlogPost() {
let { slug } = useParams();
return <div>Now showing post {slug}</div>;
}
复制代码
- 函数组件通过
({ match }) => ()
获得参数
function Article({ match }) {
return <div> {match.params.id} </div>;
}
复制代码
- 类组件通过
this.props.match
class Article extends React.Component {
render() {
const { match } = this.props;
return <div>{match.params.id}</div>;
}
}
复制代码
如果要使用 match 的话,组件必须写在 component 中(<Route component={Component} />
)。
三、路径的模糊匹配
path-to-regexp 是一个将字符串路径转换为正则表达式的的工具库,React Router 就用它来处理 url 中地址与参数。
const { pathToRegexp } = require("path-to-regexp");
复制代码
?: 匹配 0 次或 1 次
const regexp = pathToRegexp("/:foo/:bar?");
// keys = [{ name: 'foo', ... }, { name: 'bar', prefix: '/', modifier: '?' }]
regexp.exec("/test");
//=> [ '/test', 'test', undefined, index: 0, input: '/test', groups: undefined ]
regexp.exec("/test/route");
//=> [ '/test/route', 'test', 'route', index: 0, input: '/test/route', groups: undefined ]
复制代码
*:匹配 0 次或多次
const regexp = pathToRegexp("/:foo*");
// keys = [{ name: 'foo', prefix: '/', modifier: '*' }]
regexp.exec("/");
//=> [ '/', undefined, index: 0, input: '/', groups: undefined ]
regexp.exec("/bar/baz");
//=> [ '/bar/baz', 'bar/baz', index: 0, input: '/bar/baz', groups: undefined ]
复制代码
+:匹配一次或多次
const regexp = pathToRegexp("/:foo+");
// keys = [{ name: 'foo', prefix: '/', modifier: '+' }]
regexp.exec("/");
//=> null
regexp.exec("/bar/baz");
//=> [ '/bar/baz','bar/baz', index: 0, input: '/bar/baz', groups: undefined ]
复制代码
自定义匹配
通过括号包裹一个自定义的正则。
const regexpNumbers = pathToRegexp("/icon-:foo(\\d+).png");
// keys = [{ name: 'foo', ... }]
regexpNumbers.exec("/icon-123.png");
//=> ['/icon-123.png', '123']
regexpNumbers.exec("/icon-abc.png");
//=> null
const regexpWord = pathToRegexp("/(user|u)");
// keys = [{ name: 0, ... }]
regexpWord.exec("/u");
//=> ['/u', 'u']
regexpWord.exec("/users");
//=> null
复制代码
注意: 这里的匹配数字 \\d+
和正则表达式 \d+
不同,React Router 中选择 \d+
。
四、何时使用 URL 传递参数
页面状态尽量使用 URL 参数定义,扩展性更好。
比如一个考勤系统里的考勤信息页面,查询的月份信息是否要放入 URL 中?考虑到可能需要访问「指定月份」的考勤信息,所以将月份信息放任 URL 参数中更合适。
嵌套路由
嵌套路由是前端特有的概念:
- 每个 React 组件都可以是一个容器组件
- React Router 的声明式语法可以方便的定义嵌套路由
第一层路由是常规写法
export default function App() {
return (
<Router>
<div>
<ul>
<li>
<NavLink exact to="/">
Home
</NavLink>
</li>
<li>
<NavLink to="/about">About</NavLink>
</li>
<li>
<NavLink to="/topics">Topics</NavLink>
</li>
</ul>
<Switch>
<Route exact path="/">
<Home />
</Route>
<Route path="/about">
<About />
</Route>
<Route path="/topics">
<Topics />
</Route>
</Switch>
</div>
</Router>
);
}
function Home() {
return <h2>Home</h2>;
}
function About() {
return <h2>About</h2>;
}
复制代码
第二层路哟还是常规写法
Topic 组件:
function Topics() {
return (
<div>
<h2>Topics</h2>
<ul>
<li>
<NavLink to="/topics/components">Components</NavLink>
</li>
<li>
<NavLink to="/topics/props-v-state">Props v. State</NavLink>
</li>
</ul>
<Switch>
<Route path="/topics/:topicId">
<Topic />
</Route>
<Route path="/topics">
<h3>Please select a topic.</h3>
</Route>
</Switch>
</div>
);
}
复制代码
可以看到嵌套的第二层路由也是常规操作,这里利用了 <Route>
的共存属性,多次匹配同一个路径渲染不同的组件。
第一层路由匹配部分也可以用 useRouteMatch
来完成:
useRouteMatch:尝试以与相同的方式匹配当前 URL。 React-Router v5.1 新带来的 Hook。
import { useRouteMatch } from "react-router-dom";
function Topics() {
let match = useRouteMatch();
/*
{
isExact: false,
params: {},
path: "/topics",
url: "/topics",
};
*/
return (
<div>
<h2>Topics</h2>
<ul>
<li>
<NavLink to={`${match.url}/components`}>Components</NavLink>
</li>
<li>
<NavLink to={`${match.url}/props-v-state`}>Props v. State</NavLink>
</li>
</ul>
<Switch>
<Route path={`${match.path}/:topicId`}>
<Topic />
</Route>
<Route path={match.path}>
<h3>Please select a topic.</h3>
</Route>
</Switch>
</div>
);
}
复制代码
Topic 组件
import { useParams } from "react-router-dom";
function Topic() {
const { topicId } = useParams();
return <h3>Requested topic ID: {topicId}</h3>;
}
复制代码
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END