https://codesandbox.io/s/rr00y9w2wm
OR
match.params.topicId
应该与父主题组件相同,并且应该与match.params.topicId
相同。match.params.topicId
时未定义 match.params.topicId
时,将呈现 我从this closed issue了解到,这不一定是错误。
此要求在想要在Mill Web应用程序中创建运行的用户中非常常见,其中父级组件Topics
需要访问 match.params.paramId ,其中paramId
是与嵌套(子)组件Topic
相匹配的URL参数:
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} />
路线/组件。
更痛苦的是,导航菜单不必与组件树具有一对一的关系。有时,菜单根级的项目(例如Topics
,Sections
等)可能对应于嵌套结构(Sections
仅在主题/topics/:topicId/sections/:sectionId
尽管有自己的规范化列表,但导航栏中标题为 Sections 的用户可以使用。
因此,当点击 Sections 时,应突出显示 ,而不同时选中 Sections 和 Topics < / strong>。
在应用程序的根目录级别的导航栏组件上没有sectionId
或sections
路径的情况下,有必要为这种常见用例编写hacks like this。
我根本不是React Router的专家,因此,如果任何人都可以对此用例提出合适的优雅解决方案,我将认为这是富有成果的努力。优雅,我的意思是
match
而不是history.location.pathname
window.location.xxx
的hacky方法this.props.location.pathname
path-to-regexp
之类的第三方库其他黑客/部分解决方案/相关问题:
TIA!
答案 0 :(得分:6)
尝试利用查询参数?
来允许父级和子级访问当前选定的topic
。不幸的是,您将需要使用模块qs,因为react-router-dom
不会自动解析查询(react-router v3会自动解析)。
工作示例:https://codesandbox.io/s/my1ljx40r9
URL的结构类似于连接字符串:
topic?topic=props-v-state
然后您将使用&
添加到查询中:
/topics/topic?topic=optimization&category=pure-components&subcategory=shouldComponentUpdate
✔使用匹配项进行路由URL处理
✔不使用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>
);
};
另一种方法是创建一个HOC
来将参数存储到state
,并且子级的state
的参数更改时,子级会更新其父级的/topics/rendering/optimization/pure-components/shouldComponentUpdate
。
URL的结构类似于文件夹树:this.props.location.pathname
工作示例:https://codesandbox.io/s/9joknpm9jy
✔使用匹配项进行路由URL处理
✔不使用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>
);
}
✔使用lodash进行对象之间的比较
✔不涉及黑客手段
Topics.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>
);
NestedRoutes.js
document.getElementById('draw').addEventListener('click', function(){
document.getElementById('here').innerHTML =
'<svg height="100" width="100">' +
'<circle cx="50" cy="50" r="40" stroke="black" stroke-width="1" fill="rgba(130,130,130,0.6)">' +
'</svg>';
});
答案 1 :(得分:4)
React-router
不会为您提供任何已匹配子级Route的匹配参数,而是会根据当前匹配为您提供参数。因此,如果您的“路线”设置为
<Route path='/topic' component={Topics} />
在Topics
组件中,您有一条类似的路线
<Route path=`${match.url}/:topicId` component={Topic} />
现在,如果您的网址是/topic/topic1
,它与内部Route匹配,但是对于Topics组件,则匹配的Route仍然是/topic
,因此其中没有参数,这很有意义。
如果要获取主题组件中匹配的子路由的参数,则需要使用React-router提供的matchPath
实用程序,并针对要获取其参数的子路由进行测试< / p>
import { matchPath } from 'react-router'
render(){
const {users, flags, location } = this.props;
const match = matchPath(location.pathname, {
path: '/topic/:topicId',
exact: true,
strict: false
})
if(match) {
console.log(match.params.topicId);
}
return (
<div>
<Route exact path="/topic/:topicId" component={Topic} />
</div>
)
}
编辑:
获取所有级别的所有参数的一种方法是利用上下文并在上下文提供者中匹配它们时更新它们。
您需要围绕Route创建一个包装,以使其正常工作,典型示例如下
RouteWrapper.jsx
import React from "react";
import _ from "lodash";
import { matchPath } from "react-router-dom";
import { ParamContext } from "./ParamsContext";
import { withRouter, Route } from "react-router-dom";
class CustomRoute extends React.Component {
getMatchParams = props => {
const { location, path, exact, strict } = props || this.props;
const match = matchPath(location.pathname, {
path,
exact,
strict
});
if (match) {
console.log(match.params);
return match.params;
}
return {};
};
componentDidMount() {
const { updateParams } = this.props;
updateParams(this.getMatchParams());
}
componentDidUpdate(prevProps) {
const { updateParams, match } = this.props;
const currentParams = this.getMatchParams();
const prevParams = this.getMatchParams(prevProps);
if (!_.isEqual(currentParams, prevParams)) {
updateParams(match.params);
}
}
componentWillUnmount() {
const { updateParams } = this.props;
const matchParams = this.getMatchParams();
Object.keys(matchParams).forEach(k => (matchParams[k] = undefined));
updateParams(matchParams);
}
render() {
return <Route {...this.props} />;
}
}
const RouteWithRouter = withRouter(CustomRoute);
export default props => (
<ParamContext.Consumer>
{({ updateParams }) => {
return <RouteWithRouter updateParams={updateParams} {...props} />;
}}
</ParamContext.Consumer>
);
ParamsProvider.jsx
import React from "react";
import { ParamContext } from "./ParamsContext";
export default class ParamsProvider extends React.Component {
state = {
allParams: {}
};
updateParams = params => {
console.log({ params: JSON.stringify(params) });
this.setState(prevProps => ({
allParams: {
...prevProps.allParams,
...params
}
}));
};
render() {
return (
<ParamContext.Provider
value={{
allParams: this.state.allParams,
updateParams: this.updateParams
}}
>
{this.props.children}
</ParamContext.Provider>
);
}
}
Index.js
ReactDOM.render(
<BrowserRouter>
<ParamsProvider>
<App />
</ParamsProvider>
</BrowserRouter>,
document.getElementById("root")
);
答案 2 :(得分:0)
尝试执行以下操作:
<Switch>
<Route path="/auth/login/:token" render={props => <Login {...this.props} {...props}/>}/>
<Route path="/auth/login" component={Login}/>
首先是带有参数的路由,然后是没有参数的链接。
在我的Login组件内部,我将这行代码console.log(props.match.params.token);
进行了测试并为我工作。
答案 3 :(得分:0)
如果您有一组已知的子路线,则可以使用以下方式:
W1 = init_weights([100, 7*7*512])
W2 = init_weights([3, 3, 512, 256])
W3 = init_weights([3, 3, 256, 128])
W4 = init_weights([3, 3, 128, 1])
在上面的示例中,Parent将获得ExpectedTag,expectedEvent作为匹配参数,并且与子组件没有冲突,Child组件将获得activeTag,activeEvent,activeIndex作为参数。也可以使用相同名称的params,我也尝试过使用。
答案 4 :(得分:0)
如果你碰巧使用 React.FC,有一个钩子 useRouteMatch
。
例如,父组件路由:
<div className="office-wrapper">
<div className="some-parent-stuff">
...
</div>
<div className="child-routes-wrapper">
<Switch>
<Route exact path={`/office`} component={List} />
<Route exact path={`/office/:id`} component={Alter} />
</Switch>
</div>
</div>
在您的子组件中:
...
import { useRouteMatch } from "react-router-dom"
...
export const Alter = (props) => {
const match = useRouteMatch()
const officeId = +match.params.id
//... rest function code
}