简体   繁体   中英

React.js - passing props to children from hoc

I have been trying to pass some props from my HOC to children. the HOC wraps react router switch and route. The props are missing in the child component. I make use of React.CloneElement to add the props to the children but do not seem to work

<BrowserRouter>
<Layout>
        <React.Suspense fallback={loading()}>
          <Switch>
            <Route exact path="/" component={Login} />
            <Route path="/dashboard" component={Home} />
            <Route path="/tickets" component={Tickets} />

          </Switch>
        </React.Suspense>
      </Layout>
    </BrowserRouter>

this is the HOC(layout)

class Layout extends React.Component {
   .....

    render() {
        const children = this.props.children && React.cloneElement(this.props.children, { data: 'ok' })
...

the child component do no get the data prop, I get just this

{history: {…}, location: {…}, match: {…}, staticContext: undefined}

A working HOC example that injects a data prop into the base component.

 /* HOC */ const withData = Base => () => <Base data="ok" /> /* Component */ class Router extends React.Component { render() { return this.props.data; } } const RouterWithData = withData(Router); // export default withData(Router); ReactDOM.render(<RouterWithData />, document.getElementById('root'));
 <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script> <div id="root"></div>

this.props.children is a collection of elements/components. So, you have to map before calling cloneElement :

return React.Children.map(this.props.children, el => (
    React.cloneElement(el, { data: 'ok' });
); 

With HOC, you can pass props to direct children.

If you need to pass props to deeper children, you may need to use the React Context API .

For example :

// LayoutContext.js
import React from 'react';

/**
 * Create and initialize a context for the Layout component
 */
export default React.createContext({
    data: null,
});
// Layout.js
import React from 'react';
import LayoutContext from './LayoutContext';

/**
 * The Layout component which injects the context
 * All children can consume the context
 */
export default function Layout({ children }) {
    // This is where you set your data
    const data = 'my-value';

    return (
        <LayoutContext.Provider value={{ data }}>
            {children}
        </LayoutContext.Provider>
    );
}
// SomeChild.js
import React from 'react';

/**
 * How you can consume the context in any child declared in the Layout component
 * Here we are using the `useContext` hook but it works the same by using a Consumer
 */
export default function SomeChild() {
    const { data } = React.useContext(LayoutContext);

    // Do whatever you want with the data
}
// App.js
import React from 'react';
import Layout from './Layout';

export default function App() {
    return (
        <BrowserRouter>
            <Layout>
                {/* Any component in this tree can use the LayoutContext */}
            </Layout>
        </BrowserRouter>
    );
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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