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