在根级别无法访问React Router v4嵌套匹配参数 [英] React Router v4 Nested match params not accessible at root level
问题描述
https://codesandbox.io/s/rr00y9w2wm
- Click on Topics
- Click on Rendering with React
OR
-
在 Topic 组件中访问
-
match.params.topicId
时,它们与父 Topics 组件应与match.params.topicId
相同
match.params.topicId
should be identical from both the parent Topics component should be the same asmatch.params.topicId
when accessed within the Topic component
-
在主题组件中访问
-
match.params.topicId
时未定义
在主题组件中访问 -
match.params.topicId
是渲染
match.params.topicId
when accessed within the Topic component is undefinedmatch.params.topicId
when accessed within the Topics component is rendering
我从此已解决的问题理解,这不一定是错误.
I understand from this closed issue that this is not necessarily a bug.
此要求在要在Mill Web应用程序中创建运行的用户中非常常见,在该应用程序中父级组件Topics
需要访问 match.params.paramId 的用户,其中Topic
:
This requirement is super common among users who want to create a run in the mill web application where a component Topics
at a parent level needs to access the match.params.paramId where paramId
is a URL param that matches a nested (child) component Topic
:
const Topic = ({ match }) => (
<div>
<h2>Topic ID param from Topic Components</h2>
<h3>{match.params.topicId}</h3>
</div>
);
const Topics = ({ match }) => (
<div>
<h2>Topics</h2>
<h3>{match.params.topicId || "undefined"}</h3>
<Route path={`${match.url}/:topicId`} component={Topic} />
...
</div>
);
从一般意义上讲,Topics
可以是抽屉"或导航菜单"组件,而Topic
可以是任何子组件,就像我正在开发的应用程序中一样.子组件具有其自己的:topicId
参数,该参数具有其自己的(例如)<Route path="sections/:sectionId" component={Section} />
路线/组件.
In a generic sense, Topics
could be a Drawer or Navigation Menu component and Topic
could be any child component, like it is in the application I'm developing. The child component has it's own :topicId
param which has it's own (let's say) <Route path="sections/:sectionId" component={Section} />
Route/Component.
更痛苦的是,导航菜单不必与组件树具有一对一的关系.有时,菜单根级的项目(例如Topics
,Sections
等)可能对应于嵌套结构(尽管Sections
仅在主题下呈现,但/topics/:topicId/sections/:sectionId
它具有自己的标准化列表,可供用户在导航栏中的标题 Sections 下使用.
因此,当点击 Sections 时,应突出显示 ,而不同时选中 Sections 和 Topics .
Even more painful, the Navigation Menu needn't have a one-to-one relationship with the component tree. Sometimes the items at the root level of the menu (say Topics
, Sections
etc.) might correspond to a nested structure (Sections
is only rendered under a Topic, /topics/:topicId/sections/:sectionId
though it has its own normalized list that is available to the user under the title Sections in the Navigation Bar).
Therefore, when Sections is clicked, it should be highlighted, and not both Sections and Topics.
在应用程序的根目录级别的导航栏组件中没有sectionId
或sections
路径时,有必要编写
With the sectionId
or sections
path unavailable to the Navigation Bar component which is at the Root level of the application, it becomes necessary to write hacks like this for such a commonplace use case.
我根本不是React Router的专家,因此,如果任何人都可以尝试针对此用例的合适的优雅解决方案,那么我将认为这是富有成果的努力.优雅,我的意思是
I am not an expert at all at React Router, so if anyone can venture a proper elegant solution to this use case, I would consider this to be a fruitful endeavor. And by elegant, I mean
- 使用
match
而不是history.location.pathname
- 不涉及诸如手动解析
window.location.xxx
之类的黑客手段
- 不使用
this.props.location.pathname
- 不使用像
path-to-regexp
这样的第三方库
- 不使用查询参数
- Uses
match
and nothistory.location.pathname
- Does not involve hacky approaches like manually parsing the
window.location.xxx
- Doesn't use
this.props.location.pathname
- Does not use third party libraries like
path-to-regexp
- Does not use query params
其他黑客/部分解决方案/相关问题:
Other hacks/partial solutions/related questions:
TIA!
推荐答案
尝试利用查询参数?
允许父级和子级访问当前选定的topic
.不幸的是,您将需要使用模块 qs ,因为react-router-dom
不会自动解析查询(反应路由器v3确实如此).
Try utilizing query parameters ?
to allow the parent and child to access the current selected topic
. Unfortunately, you will need to use the module qs because react-router-dom
doesn't automatically parse queries (react-router v3 does).
工作示例: https://codesandbox.io/s/my1ljx40r9
URL的结构类似于连接字符串:
URL is structured like a concatenated string:
topic?topic=props-v-state
然后您将使用&
添加到查询中:
Then you would add to the query with &
:
/topics/topic?topic=optimization&category=pure-components&subcategory=shouldComponentUpdate
✔使用匹配项进行路由URL处理
✔ Uses match for Route URL handling
✔不使用this.props.location.pathname
(使用this.props.location.search
)
✔使用qs
解析location.search
✔不涉及黑客手段
Topics.js
import React from "react";
import { Link, Route } from "react-router-dom";
import qs from "qs";
import Topic from "./Topic";
export default ({ match, location }) => {
const { topic } = qs.parse(location.search, {
ignoreQueryPrefix: true
});
return (
<div>
<h2>Topics</h2>
<ul>
<li>
<Link to={`${match.url}/topic?topic=rendering`}>
Rendering with React
</Link>
</li>
<li>
<Link to={`${match.url}/topic?topic=components`}>Components</Link>
</li>
<li>
<Link to={`${match.url}/topic?topic=props-v-state`}>
Props v. State
</Link>
</li>
</ul>
<h2>
Topic ID param from Topic<strong>s</strong> Components
</h2>
<h3>{topic && topic}</h3>
<Route
path={`${match.url}/:topicId`}
render={props => <Topic {...props} topic={topic} />}
/>
<Route
exact
path={match.url}
render={() => <h3>Please select a topic.</h3>}
/>
</div>
);
};
另一种方法是创建一个将参数存储到state
的HOC
,并且子级的state
更改后,子级会更新其父级的state
.
Another approach would be to create a HOC
that stores params to state
and children update the parent's state
when its params have changed.
URL的结构类似于文件夹树:/topics/rendering/optimization/pure-components/shouldComponentUpdate
URL is structured like a folder tree: /topics/rendering/optimization/pure-components/shouldComponentUpdate
工作示例: https://codesandbox.io/s/9joknpm9jy
✔使用匹配项进行路由URL处理
✔ Uses match for Route URL handling
✔不使用this.props.location.pathname
✔使用lodash进行对象之间的比较
✔ Uses lodash for object to object comparison
✔不涉及黑客手段
Topics.js
import map from "lodash/map";
import React, { Fragment, Component } from "react";
import NestedRoutes from "./NestedRoutes";
import Links from "./Links";
import createPath from "./createPath";
export default class Topics extends Component {
state = {
params: "",
paths: []
};
componentDidMount = () => {
const urlPaths = [
this.props.match.url,
":topicId",
":subcategory",
":item",
":lifecycles"
];
this.setState({ paths: createPath(urlPaths) });
};
handleUrlChange = params => this.setState({ params });
showParams = params =>
!params
? null
: map(params, name => <Fragment key={name}>{name} </Fragment>);
render = () => (
<div>
<h2>Topics</h2>
<Links match={this.props.match} />
<h2>
Topic ID param from Topic<strong>s</strong> Components
</h2>
<h3>{this.state.params && this.showParams(this.state.params)}</h3>
<NestedRoutes
handleUrlChange={this.handleUrlChange}
match={this.props.match}
paths={this.state.paths}
showParams={this.showParams}
/>
</div>
);
}
NestedRoutes.js
import map from "lodash/map";
import React, { Fragment } from "react";
import { Route } from "react-router-dom";
import Topic from "./Topic";
export default ({ handleUrlChange, match, paths, showParams }) => (
<Fragment>
{map(paths, path => (
<Route
exact
key={path}
path={path}
render={props => (
<Topic
{...props}
handleUrlChange={handleUrlChange}
showParams={showParams}
/>
)}
/>
))}
<Route
exact
path={match.url}
render={() => <h3>Please select a topic.</h3>}
/>
</Fragment>
);
这篇关于在根级别无法访问React Router v4嵌套匹配参数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!