[英]Add props to component of wrapped route in react router v4
I have routes that share the same behauvior, layout, etc. I'd like to pass props from layout to those components (Dashboard and Login) inside Route我有共享相同行为、布局等的路由。我想将 props 从布局传递到路由内的那些组件(仪表板和登录)
My routes.js file is the following one我的 routes.js 文件如下
//imports omited
export default (
<AppLayout>
<Route component={Dashboard} path="/" key="/" />
<Route component={Login} path="/login" key="/login" />
</AppLayout>
);
The render method of AppLayout.js has this code AppLayout.js的render方法有这段代码
const childrenWithExtraProp = React.Children.map(this.props.children, (child) => {
return React.cloneElement(child, {
component: React.cloneElement(child.props.component, {
functions: {
updateMenuTitle: this.updateTitle //function
}
})
});
});
This code results on numerous errors:此代码导致许多错误:
Warning: Failed prop type: Invalid prop `component` of type `object` supplied to `Route`, expected `function`.
in Route
in AppHeader
in Router (created by BrowserRouter)
in BrowserRouter (created by App)
in App
Check the render method of `Route`.
in Route
in AppHeader
in Router (created by BrowserRouter)
in BrowserRouter (created by App)
in App
Uncaught Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
Check the render method of `Route`.
at invariant (invariant.js?7313:42)
at createFiberFromElement (react-dom.development.js?cada:5753)
at reconcileSingleElement (react-dom.development.js?cada:7531)
at reconcileChildFibers (react-dom.development.js?cada:7635)
at reconcileChildrenAtExpirationTime (react-dom.development.js?cada:7756)
at reconcileChildren (react-dom.development.js?cada:7747)
at finishClassComponent (react-dom.development.js?cada:7881)
at updateClassComponent (react-dom.development.js?cada:7850)
at beginWork (react-dom.development.js?cada:8225)
at performUnitOfWork (react-dom.development.js?cada:10224)
At the last project I've worked we where using Routes inside Route, but at React-Router v4 this is not allowed.在我工作的最后一个项目中,我们在 Route 中使用了 Routes,但在 React-Router v4 中这是不允许的。
Edit: before was something like this:编辑:以前是这样的:
//Array of routes declared before
export default (
<Router history={browserHistory}>
<Route path="/" component={General}>
<IndexRoute component={Index} />
{routes}
</Route>
</Router>
);
I suspect this is the issue:我怀疑这是问题所在:
component: React.cloneElement(child.props.component, {
child.props.component
isn't a rendered component (like <Dashbard />
), it's a component class (like Dashboard
). child.props.component
不是渲染组件(如<Dashbard />
),它是一个组件类(如Dashboard
)。 cloneElement
expects a rendered component. cloneElement
需要呈现的组件。 And you can't explicitly pass props extra into a component class .并且您不能显式地将 props extra 传递到组件类中。
There are a few ways you can achieve what you're doing.有几种方法可以实现您正在做的事情。 Cloning a Route feels "tricky" to me.
克隆路线对我来说感觉“棘手”。
updateTitle
logicupdateTitle
逻辑的高阶组件I would personally try making a higher order component (a function that takes a component class and returns a component class) that adds this prop, and exporting your Dashboard/Login components wrapped in it.我个人会尝试制作一个高阶组件(一个接受组件类并返回一个组件类的函数)来添加此道具,并导出包含在其中的仪表板/登录组件。 Slightly more verbose but not as tricky:
稍微冗长但不那么棘手:
HOC file: HOC 文件:
const WithExtraProp = (ContentComponent) => {
return WithPropWrapper extends Component {
updateMenuTitle() {...}
render() {
// Add extra props here
return <ContentComponent {...this.props} functions={{ updateMenuTitle: this.updateMenuTitle }}/>
}
}
}
export default WithExtraProp;
And in Dashboard并在仪表板中
class Dashboard extends Component {...}
export default WithExtraProp(Dashboard);
With this method, you could also do (although I like it less)用这个方法,你也可以做(虽然我不太喜欢)
<AppLayout>
<Route component={WithExtraProp(Dashboard)} path="/" key="/" />
<Route component={WithExtraProp(Login)} path="/login" key="/login" />
</AppLayout>
<Route render={} />
instead of component={}
to add props<Route render={} />
而不是component={}
添加道具If you want to keep your current setup, where you implicitly/"magically" add props , I don't see a way to do it without using the Route's render
prop instead of component
.如果你想保留你当前的设置,你隐式/“神奇地”添加 props ,我看不到不使用 Route 的
render
prop 而不是component
。 This way you can render the component and pass in props normally.这样你就可以渲染组件并正常传入 props。
You can keep this the same:您可以保持不变:
<Route component={Dashboard} path="/" key="/" />
And something like this:和这样的事情:
const childrenWithExtraProp = React.Children.map(this.props.children, (child) => {
// Clone the <Route />, remove the `component` prop, add `render` prop
return React.cloneElement(child, {
// Remove the `component` prop from the Route, since you can't use
// `component` and `render` on a Route together. This way component
// just becomes an API for this withExtraPropClass to use to find
// the right component
component: null,
render = () => {
const ChildComponent = child.props.component;
const functions = {
updateMenuTitle: this.updateTitle //function
};
return <ChildComponent functions={functions} />;
}
})
});
});
AppLayout
a higher order componentAppLayout
成为高阶组件This is the same as option 1, where in the end you do this:这与选项 1 相同,最终您执行以下操作:
//imports omited
export default (
<Route component={Dashboard} path="/" key="/" />
<Route component={Login} path="/login" key="/login" />
);
And AppLayout
is a higher order component that adds the prop.而
AppLayout
是一个添加 prop 的高阶组件。
const AppLayout = (ContentComponent) => {
return WithPropWrapper extends Component {
updateMenuTitle() {...}
render() {
// Add extra props here
return (
<MyLayoutStuff>
<ContentComponent {...this.props} functions={{ updateMenuTitle: this.updateMenuTitle }}/>
</MyLayoutStuff>
);
}
}
}
export default AppLayout;
and export your components wrapped in the layout:并导出包裹在布局中的组件:
class Dashboard extends Component {...}
export default AppLayout(Dashboard);
I personally have been using something closest to #3.我个人一直在使用最接近 #3 的东西。 Specifically, I have a file like
dashboard/Dashboard.js
, and in that same folder, dashboard/index.js
, which exports Dashboard wrapped in a layout.具体来说,我有一个类似
dashboard/Dashboard.js
文件,在同一个文件夹中, dashboard/index.js
,它导出包裹在布局中的 Dashboard。 You can see an example of that pattern at this React boilerplate Github folder .您可以在这个 React 样板 Github 文件夹中看到该模式的示例。
There are other options too.还有其他选择。 You could make an
<AppRoutes children=[{component: Dashboard, path="/"}, {...}] />
component that doesn't have to deal with cloning.你可以制作一个
<AppRoutes children=[{component: Dashboard, path="/"}, {...}] />
组件,它不必处理克隆。 If you need to do things with children on top of just <render>
ing them, I generally prefer passing them in as an array instead of child components and mapping over them.如果你需要在
<render>
之上对孩子做一些事情,我通常更喜欢将它们作为数组而不是子组件传入并映射它们。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.