Default.HOC.js
import React from "react";
import { Route, Routes } from "react-router-dom";
import DefaultLayout from "../layouts/Default.layout";
const DefaultHOC = ({ component: Component, ...rest }) => {
// component
// props -> path exact
return (
<Routes>
<Route
{...rest}
component = {(props) => {
<DefaultLayout>
<Component {...props} />
</DefaultLayout>
}}
/>
</Routes>
);
};
export default DefaultHOC;
temp.js
import React from "react";
function Temp() {
return <h1>This is a temp component</h1>
}
export default Temp;
Default.layout.js
import React from "react";
const DefaultLayout = (props) => {
return (
<div style={{ padding: '10px' }}>
<h1>Default Layout Page</h1>
{props.children}
</div>
);
};
export default DefaultLayout;
App.js
import { Route, Routes } from "react-router-dom";
// HOC
import DefaultHOC from "./HOC/Default.HOC";
// Component
import Temp from "./components/temp";
function App() {
return (
<>
<DefaultHOC path="/" exact element={<Temp />} />
</>
);
}
export default App;
The video lecture I'm following has used the older version, the problem is that when I'm calling children
, only the Temp
is being rendered, i.e, the screen only shows:
"This is a temp component"
whereas it should show the result as:
"Default Layout Page This is a temp component"
I've tried replacing component
with element
, it shows the same result. Also, when I remove the destructured props and all, it only shows "Default layout page".
DefaultHOC
is misnamed, it's not a Higher Order Component, e.g. a function component that returns a function component, it's just a regular React function component.DefaultHOC
needs to render the Route
correctly, e.g. passing the correct props. There is no component
prop, there exists only a single element
prop that takes a React.ReactNode
, e.g. JSX, as an argument.The current code only renders the <Temp />
component because it was passed to DefaultHOC
on the element
prop which was spread through to the Route
component along with the path
prop. The component
prop is ignored.
<DefaultHOC path="/" exact element={<Temp />} />
const DefaultHOC = ({ component: Component, ...rest }) => {
return (
<Routes>
<Route
{...rest} // <-- path and element pass through here
component={(props) => { // <-- extraneous ignored prop
<DefaultLayout>
<Component {...props} />
</DefaultLayout>;
}}
/>
</Routes>
);
};
Refactor the DefaultHOC
to render DefaultLayout
and passed component
prop on the Route
component's element
prop. I suggest also renaming the component since it's not a HOC.
Example:
const DefaultComponent = ({ component, ...props }) => {
return (
<Routes>
<Route {...props} element={<DefaultLayout>{component}</DefaultLayout>} />
</Routes>
);
};
<DefaultComponent path="/" component={<Temp />} />
The above appears to be a very unconventional method is sharing UI via a layout. The idiomatic way to render certain components into certain UIs in react-router@6
is to use Layout Routes. Layout routes render "common UI" and possibly house "common state/logic" and render an Outlet
for nested routes to render their content into.
Example:
import { Outlet } from "react-router-dom";
const DefaultLayout = () => {
return (
<div style={{ padding: "10px" }}>
<h1> Default Layout Page </h1>
<Outlet />
</div>
);
};
App.js
import { Route, Routes } from "react-router-dom";
...
export default function App() {
return (
<Routes>
<Route element={<DefaultLayout />}>
<Route path="/" element={<Temp />} />
</Route>
</Routes>
);
}