我正在使用React,React-Router(v5)和Redux构建应用程序,并想知道如何在父路径中访问当前URL的参数。
这是我的参赛作品router.js
:
<Wrapper>
<Route exact path="/login" render={(props) => (
<LoginPage {...props} entryPath={this.entryPath} />
)} />
<Route exact path="/" component={UserIsAuthenticated(HomePage)} />
<Route exact path="/about" component={UserIsAuthenticated(AboutPage)} />
<Route path="/projects" component={UserIsAuthenticated(ProjectsPage)} />
</Wrapper>
这是我的ProjectsPage
组件:
class ProjectsPage extends PureComponent {
componentDidMount() {
this.props.fetchProjectsRequest()
}
render() {
console.log(this.props.active)
if (this.props.loading) {
return <Loading />
} else {
return (
<Wrapper>
<Sidebar>
<ProjectList projects={this.props.projects} />
</Sidebar>
<Content>
<Route exact path="/projects" component={ProjectsDashboard} />
<Switch>
<Route exact path="/projects/new" component={ProjectNew} />
<Route exact path="/projects/:id/edit" component={ProjectEdit} />
<Route exact path="/projects/:id" component={ProjectPage} />
</Switch>
</Content>
</Wrapper>
)
}
}
}
const enhance = connect(
(state, props) => ({
active: props.match,
loading: projectSelectors.loading(state),
projects: projectSelectors.projects(state)
}),
{
fetchProjectsRequest
}
)
export default withRouter(enhance(ProjectsPage))
问题是,虽然网址为console.log
,但我render
方法中的{"path":"/projects","url":"/projects","isExact":false,"params":{}}
输出为http://localhost:3000/projects/14
。
我想在ID
添加ProjectList
道具以突出显示当前所选项目。
我可以在我的ProjectPage
组件中的商店中保存项目的ID,但我认为这会有点混乱,特别是因为URL实际上有信息 - 所以我为什么要在店?
另一个(糟糕的?)方法是解析位置对象自己获取ID,但我认为有一种react-router
/ react-router-redux
方法来获取这个参数被忽视了。
答案 0 :(得分:10)
@Kyle从技术角度解释了问题。 我将专注于解决这个问题。
您可以使用matchPath
获取所选项目的id
。
matchPath - https://reacttraining.com/react-router/web/api/matchPath
这使您可以使用与使用except相同的匹配代码 在正常的渲染周期之外,就像收集数据一样 在服务器上呈现之前的依赖关系。
在这种情况下的用法非常简单。
matchPath
// history is one of the props passed by react-router to component
// @link https://reacttraining.com/react-router/web/api/history
const match = matchPath(history.location.pathname, {
// You can share this string as a constant if you want
path: "/articles/:id"
});
let articleId;
// match can be null
if (match && match.params.id) {
articleId = match.params.id;
}
articleId
{articleId && (
<h1>You selected article with id: {articleId}</h1>
)}
我构建了一个简单的演示,您可以使用它在项目中实现相同的功能。
演示: https://codesandbox.io/s/pQo6YMZop
我认为这个解决方案非常优雅,因为我们使用官方react-router
API,它也用于路由器中的路径匹配。我们也不在这里使用window.location
,因此如果您导出原始组件,测试/模拟也会很容易。
答案 1 :(得分:2)
<强> TLDR 强>
如果您的match.params
<Route />
媒体资源不包含path
,则 React路由器:params
将为空对象。
解决此用例:您可以在父路由的组件中使用let id = window.location.pathname.split("/").pop();
来获取ID。
详细原因
如果提供给path
的{{1}}道具没有任何参数,例如<Route />
,则路由器不会为您进行解析。如果您在第56行查看/:id
,就可以开始了解matchPath.js
道具是如何构建的。
match
然后我们可以查看第43行,您可以看到return {
path: path, // the path pattern used to match
url: path === '/' && url === '' ? '/' : url, // the matched portion of the URL
isExact: isExact, // whether or not we matched exactly
params: keys.reduce(function (memo, key, index) {
memo[key.name] = values[index];
return memo;
}, {})
};
来自keys
。然后,我们可以查看_compilePath.keys
函数并看到它使用compilePath
,它将使用pathToRegexp()
,它将使用stringToRegexp()
,然后将tokensToRegExp()
变更keys
第{355行keys.push(token)
。如果<Route />
道具中path
没有参数值,则parse()
中使用的stringToRegexp()
函数将不会返回任何令牌,甚至不会达到#355行因为唯一的标记数组不包含任何标记对象。
所以....如果你的<Route />
没有:params
,那么键值将是一个空数组,并且match
上没有任何参数。
总之,如果您的路线没有考虑到它们,您似乎必须自己获得参数。你可以使用let id = window.location.pathname.split("/").pop()
。