Home > other >  React How to send a prop to a functional component being used inside of a HOC?
React How to send a prop to a functional component being used inside of a HOC?

Time:09-10

I'm curious if it is possible to achieve this when using functional components?

Inside of my App.js, found in the first code snippet below, I want to send a Component (here: PageMain) with some props to the HOC.

When trying to do this by sending a JSX with the resp. prop, I receive the ff. error:

Warning: React.jsx: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: . Did you accidentally export a JSX literal instead of a component?

Which makes sense according to the description, because I am trying to send this instead of an actual Component:

<PageMain childContent={<p>Hey I'm the child component content!</p>

But is there a clean way to achieve this? My idea is to forward the prop to the ultimate receiver, so PageMain can work with

{props.childContent && <>props.childContent</>}

My App.js:

import { PageMain } from "./MyHOCStuff/PageMain";
import { Header } from "./MyHOCStuff/Header";
import { Footer } from "./MyHOCStuff/Footer";
import { withLayout } from "./MyHOCStuff/withLayout";

const PageWithLayout = withLayout(<PageMain childContent={<p>Hey I'm the child component content!</p>} />, Header, Footer)

function App() {
  return (
    <>
      <PageWithLayout message={"Hello from within a HOC."} />
    </>
  );
}

export default App;

My HOC:

import React from "react";
export const withLayout = (PageComponent, HeaderComponent, FooterComponent) => {
  return function WithPage({ ...props }) {
    console.log(PageComponent.props);
    return (
      <div>
        <HeaderComponent />
        {props.message && <h1>{props.message}</h1>}
        <PageComponent />
        <FooterComponent />        
      </div>
    );
  };
};

The Component, which should ultimately receive the prop:

export const PageMain = ({...props}) =>{
    return <>
        <h2>Page Content Stuff</h2>
        <p>Lorem ipsum dolor sit amet, consectetur adip bla bla bla...</p>
        {props.childContent && <>props.childContent</>}

    </>;
}

CodePudding user response:

The proper way to render a component from props is to call it like this {componentFromProps}. Note that you dont really need that childContent props, when you nest content inside a JSX tag, the parent component will receive that content in a prop called children. You can then render it like I did with PageMain.

import React from "react";

export const withLayout = (PageComponent, HeaderComponent, FooterComponent) => {
    return function WithPage(props) {
        return (
            <div>
                {HeaderComponent}
                {props.message && <h1>{props.message}</h1>}
                {PageComponent}
                {FooterComponent}
            </div>
        );
    };
};
const PageMain = ({children}) => {
    return <>
        <h2>Page Content Stuff</h2>
        <p>Lorem ipsum dolor sit amet, consectetur adip bla bla bla...</p>
        {children}
    </>;
}

const Header = <header>my header</header>
const Footer = <footer>my footer</footer>
const PageWithLayout = withLayout(<PageMain><p>Hey I'm the child component content!</p></PageMain>, Header, Footer)

function App() {
    return (
        <>
            <PageWithLayout message={"Hello from within a HOC."}/>
        </>
    );
}


export default App;

CodePudding user response:

Have you tried passing child content like this?

() => <p>Hey I'm the child component content!</p>

Also, it strikes me that there is an easier way to build your layout using the router:

import { BrowserRouter, Routes, Route } from 'react-router-dom'
import Header from 'Components/Layout/Header/Header'
import Footer from 'Components/Layout/Footer/Footer'
import PageA from 'Components/Page/PageA/PageA'
import PageB from 'Components/Page/PageB/PageB'

function App () {
  return (
    <BrowserRouter>
      <Header/>
      <Routes>
        <Route path="/foo" element={<PageA/>}/>
        <Route path="/bar" element={<PageB/>}/>
      </Routes>
      <Footer/>
    </BrowserRouter>
  )
}

export default App
  • Related