繁体   English   中英

将 props 添加到 react router v4 中包裹路由的组件

[英]Add props to component of wrapped route in react router v4

我有共享相同行为、布局等的路由。我想将 props 从布局传递到路由内的那些组件(仪表板和登录)

我的 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)

在我工作的最后一个项目中,我们在 Route 中使用了 Routes,但在 React-Router v4 中这是不允许的。

编辑:以前是这样的:

//Array of routes declared before
export default (
    <Router history={browserHistory}>
        <Route path="/" component={General}>
            <IndexRoute component={Index} />
            {routes}
        </Route>
    </Router>
);

我怀疑这是问题所在:

component: React.cloneElement(child.props.component, {

child.props.component不是渲染组件(如<Dashbard /> ),它是一个组件类(如Dashboard )。 cloneElement需要呈现的组件。 并且您不能显式地将 props extra 传递到组件类中

有几种方法可以实现您正在做的事情。 克隆路线对我来说感觉“棘手”。

选项 1:具有updateTitle逻辑的高阶组件

我个人会尝试制作一个高阶组件(一个接受组件类并返回一个组件类的函数)来添加此道具,并导出包含在其中的仪表板/登录组件。 稍微冗长但不那么棘手:

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>

选项 2:使用<Route render={} />而不是component={}添加道具

如果你想保留你当前的设置,你隐式/“神奇地”添加 props ,我看不到不使用 Route 的render prop 而不是component 这样你就可以渲染组件并正常传入 props。

您可以保持不变:

<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} />;
        }
        })
    });
});

选项 3:使AppLayout成为高阶组件

这与选项 1 相同,最终您执行以下操作:

//imports omited
export default (
    <Route component={Dashboard} path="/" key="/" />
    <Route component={Login} path="/login" key="/login" />
);

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;

并导出包裹在布局中的组件:

class Dashboard extends Component {...}
export default AppLayout(Dashboard);

其他想法

我个人一直在使用最接近 #3 的东西。 具体来说,我有一个类似dashboard/Dashboard.js文件,在同一个文件夹中, dashboard/index.js ,它导出包裹在布局中的 Dashboard。 您可以在这个 React 样板 Github 文件夹中看到该模式的示例。

还有其他选择。 你可以制作一个<AppRoutes children=[{component: Dashboard, path="/"}, {...}] />组件,它不必处理克隆。 如果你需要在<render>之上对孩子做一些事情,我通常更喜欢将它们作为数组而不是子组件传入并映射它们。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM