簡體   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