简体   繁体   English

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

[英]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.克隆路线对我来说感觉“棘手”。

Option 1: Higher order component with updateTitle logic选项 1:具有updateTitle逻辑的高阶组件

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>

Option 2: Use <Route render={} /> instead of component={} to add props选项 2:使用<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} />;
        }
        })
    });
});

Option 3: Make AppLayout a higher order component选项 3:使AppLayout成为高阶组件

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

Other thoughts其他想法

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.

相关问题 将道具传递给组件React Router V4 - Pass props to a component, React Router V4 React-Router V4-将道具传递给“路线组件”中的“渲染”功能以生成新组件 - React-Router V4 - Passing Props to Render function in Route Component to generate new component react-router v4的Route不会将它的道具传递给组件 - 在React Typescript中 - react-router v4's Route doesn't pass it's props to component - in React Typescript 如何使用React Router v4将Redux props传递到不同路径中的单独组件? - How do I pass Redux props to a separate component in a different Route with React Router v4? 将自定义道具传递给 react-router v4 中的路由器组件 - Passing custom props to router component in react-router v4 react-router v6 包裹的路由组件不工作 - react-router v6 wrapped route component not working React Router v4:组件和子代处于同一路径 - React Router v4: Component and Children in the same route React Router v4阻止运行父路由组件 - React Router v4 prevent from running parent route component React Router v4 未在带有参数的路由中渲染组件 - React Router v4 not rendering component in route w/ parameters 使用React Router V4重定向到ReactJS组件上的服务器路由 - Redirect to server route on ReactJS component using React Router V4
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM