ReactJS remove root component on certain page - javascript

I am looking for a solution that will remove a <header/> and <footer/> component from my signup.js and signin.js pages.
Currently, my root index.js file is shown as
class Template extends React.Component {
render() {
const { children } = this.props
return (
<main>
<Header/>
{children()}
<Footer/>
</main>
)
}}
Template.propTypes = {
children: PropTypes.func
}
export default Template
Which is the main layout for all my page, posts, products, etc. Yet without creating another layout, I would like to conditionally remove the <header/> and <footer/> components from being a part of pages signup.js and signin.js
As suggested by GatsbyJS I have tried - of which is removing the components from all pages.
if (this.props.location.pathname !== "/signup/") {
return (
<main>
{children()}
</main>
)
} else {
return this (
<main>
<Header/>
{children()}
<Footer/>
</main>
)
}

I would use a different template for your signin and signup components, but if you don't do that:
You have a typo in your code, in your else you are returning this(...) it should return (...). This way:
if (this.props.location.pathname !== "/signup/") {
return (
<main>
{children()}
</main>
)
} else {
return (
<main>
<Header/>
{children()}
<Footer/>
</main>
)
}
Also, perhaps your if condition is inverted... because in /signup/ you don't want Header and Footer:
if (this.props.location.pathname === "/signup/" || this.props.location.pathname === "/signin/") {
return (
<main>
{children()}
</main>
)
} else {
return (
<main>
<Header/>
{children()}
<Footer/>
</main>
)
}

Alternatively, if you don't want to duplicate code...
const isSignIn = ["/signup/", "/signin/"].indexOf( this.props.location.pathname) !== 0;
return (
<main>
{ !isSignIn && (<Header/>) }
{children()}
{ !isSignIn && (<Footer/>) }
</main>
)

Related

How to correctly pass a callback and a state to the Layout element in React Router Dom?

How to correctly pass callbacks and states to the Layout so that they can be used elsewhere? When I share this as below, I have errors and a white screen:
class Menu extends Component {
constructor(props) {
super(props);
this.onSearchF = this.onSearchF.bind(this)
}
state = {
searchBlock: false,
};
onSearchF = (keyword) => {
const filtered = this.state.data.filter((entry) =>
Object.values(entry).some(
(val) => typeof val === "string" && val.toLowerCase().includes(keyword.toLowerCase())
)
);
};
render() {
return (
<div className="content">
<Routes>
<Route path="/" element={<Layout searchBlock={this.state.searchBlock} onSearch={()=>this.onSearchF()}/>}>
<Route
index
element={
<Home data={this.state.data} num={this.state.data.length} />
}
/>
</Route>
</Routes>
</div>
);
}
}
export default Menu;
Here I pass the callback to the Header that I previously passed to the Layout:
const Layout = () => {
return (
<>
<Header sblock={this.props.searchBlock} onS = {this.props.onSearch}/>
</>
);
};
export default Layout;
I want to use the callback here:
function Header() {
return (
<header className="header">
<button onClick={()=>console.log(this.props.sblock)}>button</button>
</header>
);
}
export default Header;
Your Layout is a functional component, and you are trying to use this.props in it; this is incorrect. Get the props as part of arguments instead, like so:
import { Outlet } from "react-router-dom";
const Layout = ({searchBlock,onSearch}) => {
return (
<>
<Header sblock={searchBlock} onS={onSearch}/>
<Outlet/>
</>
);
};
export default Layout;
Issues
The Layout component isn't accepting any props.
The Layout component isn't rendering an Outlet for nested routes.
Solution
It seems that Layout only exists to render the Header component. I'd suggest rendering Header directly in the Main component.
Example:
class Menu extends Component {
state = {
data: [],
searchBlock: false,
};
onSearch = (keyword) => {
const filtered = this.state.data.filter((entry) =>
Object.values(entry).some((val) =>
typeof val === "string"
&& val.toLowerCase().includes(keyword.toLowerCase())
)
);
... do something with filtered ...
};
render() {
const { data, searchBlock } = this.state;
return (
<div className="content">
<Header sblock={searchBlock} onS={this.onSearch} />
<Routes>
<Route
path="/"
element={<Home data={data} num={data.length} />}
/>
</Routes>
</div>
);
}
}
export default Menu;

Received `true` for a non-boolean attribute `exact`

How to pass this warning?
Code
const Main = (header, navigation) => {
return (
<>
<div>
{navigation !== false && <Navigation />}
</div>
</>
)
}
i tried this but still have the same warning
<Main navigation>
....
</Main>
Console output true
<Main navigation={true}>
....
</Main>
Console output true
<Main navigation={+true}>
....
</Main>
Console output 1
<Main>
....
</Main>
Console output undefined
use this code:
const Main = (header, navigation) => {
if (navigation !== false) return <Navigation />
return <></>
}
Try this:
const Main = (header, navigation) => {
return (
!!navigation ? <Navigation />:<></>
)
}

Add different navbar on different pages with layout.js next js

I've two navbar layout and ten pages in my next js project. Now I need to set navbar one for five pages and navbar two for rest of the pages with layout.js at once. How can I do this. If anyone help me about this, I'll be very thankful. Thanks in advance.
NavbarOne.js
const NavbarOne = () => {
return (
<div>
<h1>Navbar One</h1>
</div>
);
}
export default NavbarOne;
NavbarTwo.js
const NavbarTwo = () => {
return (
<div>
<h1>Navbar Two</h1>
</div>
);
}
export default NavbarTwo;
Layout.js
import Footer from "../Footer";
import NavbarOne from "../Navbar/NavbarOne";
const Layout = ({ children }) => {
return (
<div>
<NavbarOne />
{/* <NavbarTwo /> */}
{children}
<Footer />
</div>
);
}
export default Layout;
_app.js
import Layout from '../components/layout/Layout';
import '../styles/styles.scss'
function MyApp({ Component, pageProps }) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
);
}
export default MyApp
Updated
Layout.js
import Footer from "../Footer";
import NavbarOne from "../Navbar/NavbarOne";
import NavbarTwo from "../Navbar/NavbarTwo";
const Layout = ({ children, criteria}) => {
return (
<div>
{ criteria ?
<NavbarOne />
:
<NavbarTwo />
}
{children}
<Footer />
</div>
);
}
export default Layout;
__app.js
import Layout from '../components/layout/Layout';
import '../styles/styles.scss'
function MyApp({ Component, pageProps }) {
return (
<Layout criteria={true}>
<Component {...pageProps} />
</Layout>
);
}
export default MyApp
__admission.js
import Layout from "../components/layout/Layout";
const admission = () => {
return (
<Layout criteria={false}>
<div>
<h1>Admission</h1>
</div>
</Layout>
);
}
export default admission;
You can do something like
const Layout = ({ children, criteria }) => {
return (
<div>
{ criteria ? //ternary operator
<NavbarOne />
:
<NavbarTwo />
}
{children}
<Footer />
</div>
);
}
export default Layout;
And pass a boolean to your Layout as criteria to choose between Navbars
const Page1 = () => {
return (
<Layout criteria={true}> // will display navbar 1
<p>Im page 1</p>
</Layout>
);
}
export default Layout;
const Page2 = () => {
return (
<Layout criteria={false}> // will display navbar 2
<p>Im page 2</p>
</Layout>
);
}
export default Layout;
With three navbars you can do
const Layout = ({ children, navbarType }) => {
return (
<div>
{ navbarType == 1 && <NavbarOne />}
{ navbarType == 2 && <NavbarTwo />}
{ navbarType == 3 && <NavbarThree />}
{children}
<Footer />
</div>
);
}
export default Layout;
And pass a number to your Layout as navbarType to choose between Navbars
const Page1 = () => {
return (
<Layout navbarType={1}> // will display navbar 1
<p>Im page 1</p>
</Layout>
);
}
export default Layout;
const Page2 = () => {
return (
<Layout navbarType={2}> // will display navbar 2
<p>Im page 2</p>
</Layout>
);
}
export default Layout;
const Page3 = () => {
return (
<Layout navbarType={3}> // will display navbar 3
<p>Im page 3</p>
</Layout>
);
}
export default Layout;
If you prefer an option where, you want to add N number of navbars.
and select them by some index number.
import Footer from "../Footer";
import NavbarOne from "../Navbar/NavbarOne";
const Layout = ({ children, index }) => {
const navBarList = [<NavbarOne />, <NavbarTwo />];
const renderNavBar = (_index) => navBarList[_index];
return (
<div>
{renderNavBar(index)}
{children}
<Footer />
</div>
);
}
export default Layout;
In your where you calling your app, you should be calling it as such.
import Layout from './components/layout.js';
export default function Home() {
return (
<div>
<Layout index={1}>
<p>byebye</p>
</Layout>
</div>
);
}
You can pass a props called navbar to the Layout Component like this:
export default function PageOne() {
return (
<Layout navbar="one">
<div className="container">
<h1>Page One</h1>
</div>
</Layout>
)
}
export default function PageTwo() {
return (
<Layout navbar="two">
<div className="container">
<h1>Page Two</h1>
</div>
</Layout>
)
}
And later render the Navbar Components conditionally like this:
const Layout = ({ children, navbar }) => {
return (
<div>
{ navbar === 'one' && <NavbarOne />}
{ navbar === 'two' && <NavbarTwo />}
{children}
<Footer />
</div>
);
}

Next Auth useSession returning undefined on initial page load

I have an issue where my Next Auth useSession function is returning undefined on intial page load but works when hitting refresh on the page. Here is the code:
<Navigation />
import { useSession, signIn, signOut } from 'next-auth/client'
export default function Navigation() {
const [session] = useSession()
return (
<section className="navigation">
{!session ? (
<div onClick={handleSignin} className="loginLink">Login</div>
) : ( //Do Logged ins stuff )}
</section>
)
}
<Layout>
const Layout = (layoutProps) => (
<motion.main initial="hidden" animate="enter" exit="exit" variants={variants}>
<div className="Layout">
<Head>
<title>My Site</title>
</Head>
<Navigation />
<div className="Content">{layoutProps.children}</div>
<Footer />
</div>
</motion.main>
)
index.js
class Home extends React.Component {
render() {
return (
<Layout>
//Home page stuff
</Layout>
)
}
}
export default Home
App.js
render() {
const { Component } = this.props
return (
<>
<GlobalStyles />
<AnimatePresence
exitBeforeEnter
initial={false}
onExitComplete={() => window.scrollTo(0, 0)}
>
<Component key={Router.router != null ? Router.router.asPath : '/null'} {...this.props} />
</AnimatePresence>
</>
)
}
Simple stuff. Not sure what's going on. I hope that's enough to work with.
Try implementing Provider in App.js.
Here's an example from the documentation for v3: https://next-auth.js.org/v3/getting-started/example#add-session-state
//pages/_app.js
import { Provider } from "next-auth/client"
export default function App({ Component, pageProps }) {
return (
<Provider session={pageProps.session}>
<Component {...pageProps} />
</Provider>
)
}
You should add the session provider in your _app.js file.

Wrapping functional JSX components with other functions

I want to create a functional component that wraps other components and uses JSX in its render method. I've seen a lot of content online about how to do this with class components, but I'm curious if it works with functional components.
function WrappedContent() {
return <p>I'm wrapped</p>
}
function Wrapper(WrappedComponent) {
return (
<div>
<p>Wrapped: </p>
<WrappedComponent />
</div>
)
};
function App() {
return (
<div>
<Wrapper>
<WrappedContent />
</Wrapper>
</div>
)
}
I'm guessing it has something to do with how child components are passed into <Wrapper> (via props.children?).
Here's a codesandbox with the above code: https://codesandbox.io/embed/gifted-cray-bqswi
(via props.children?)
Yes:
function WrappedContent() {
return <p>I'm wrapped</p>
}
function Wrapper(props) {
return (
<div>
<p>Wrapped: </p>
{props.children}
</div>
)
}
function App() {
return (
<div>
<Wrapper>
<WrappedContent />
</Wrapper>
</div>
)
}
ReactDOM.render(<App/>, document.getElementById("root"));
<div id="root"></div>
<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>
Note that Wrapper accepts a parameter called props, and uses props.children. You could do it with destructuring if you don't have any other props (or even if you do, but it's a small number):
function Wrapper({children}) {
return (
<div>
<p>Wrapped: </p>
{children}
</div>
)
}
What gets passed to functional components is the props, and child elements are contained in props.children:
function WrappedContent() {
return <p>I'm wrapped</p>
}
function Wrapper(props) { // <-- here
return (
<div>
<p>Wrapped: </p>
{props.children} // <-- here
</div>
)
};
function App() {
return (
<div>
<Wrapper>
<WrappedContent />
</Wrapper>
</div>
)
}
https://codesandbox.io/embed/priceless-borg-brlbk
You can try something like this.
function WrappedContent() {
return <p>I'm wrapped</p>
}
function Wrapper(props) {
return (
<div>
<p>Wrapped: </p>
{props.children}
</div>
)
};
function App() {
return (
<div>
<Wrapper>
<WrappedContent />
</Wrapper>
</div>
)
}
You might also want to refer at this article https://reactjs.org/docs/composition-vs-inheritance.html

Categories

Resources