我有共享相同行为,布局等的路线。我想将布局中的道具传递给路线内的那些组件(仪表板和登录)
我的routes.js文件是以下一个
//imports omited
export default (
<AppLayout>
<Route component={Dashboard} path="/" key="/" />
<Route component={Login} path="/login" key="/login" />
</AppLayout>
);
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
}
})
});
});
此代码导致许多错误:
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)
在上一个项目我工作过,我们在路由中使用路由,但在React-Router v4这是不允许的。
编辑:之前是这样的:
//Array of routes declared before
export default (
<Router history={browserHistory}>
<Route path="/" component={General}>
<IndexRoute component={Index} />
{routes}
</Route>
</Router>
);
答案 0 :(得分:1)
我怀疑这是问题所在:
component: React.cloneElement(child.props.component, {
child.props.component
不是呈现的组件(如<Dashbard />
),它是组件类(如Dashboard
)。 cloneElement
期望渲染的组件。并且您无法明确地将道具额外传递到组件类。
有几种方法可以实现您的目标。克隆一条路线对我来说感觉“棘手”。
updateTitle
逻辑我个人会尝试制作一个更高阶的组件(一个带有组件类并返回组件类的函数),它会添加这个prop,并导出包含在其中的Dashboard / Login组件。稍微冗长但不那么棘手:
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;
在仪表板中
class Dashboard extends Component {...}
export default WithExtraProp(Dashboard);
使用这种方法,你也可以(尽管我更喜欢它)
<AppLayout>
<Route component={WithExtraProp(Dashboard)} path="/" key="/" />
<Route component={WithExtraProp(Login)} path="/login" key="/login" />
</AppLayout>
<Route render={} />
代替component={}
添加道具 如果你想保留你当前的设置,你暗中/“神奇地”添加道具,我没有办法在不使用Route的render
道具的情况下做到这一点component
。这样你就可以渲染组件并正常传递道具。
您可以保持相同:
<Route component={Dashboard} path="/" key="/" />
这样的事情:
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
成为更高阶的组件这与选项1相同,最后您执行此操作:
//imports omited
export default (
<Route component={Dashboard} path="/" key="/" />
<Route component={Login} path="/login" key="/login" />
);
AppLayout
是一个更高阶的组件,用于添加道具。
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;
并导出包含在布局中的组件:
class Dashboard extends Component {...}
export default AppLayout(Dashboard);
我个人一直在使用最接近#3的东西。具体来说,我有一个像dashboard/Dashboard.js
这样的文件,并在同一文件夹dashboard/index.js
中导出包含在布局中的仪表板。您可以在this React boilerplate Github folder找到该模式的示例。
还有其他选择。您可以创建一个不需要处理克隆的<AppRoutes children=[{component: Dashboard, path="/"}, {...}] />
组件。如果您需要在<render>
之前对孩子进行处理,我通常更喜欢将它们作为数组而不是子组件传递给它们并映射它们。