Have a common header layout in nextjs - reactjs

I have 2 pages user.js and nonuser.js and one component header. user.js and nonuser.js have same functionality with slight changes in UI. Now I want to integrate all this. Like when I visit the page by default table of user.js must be viewed. One click of nonuser.js it should change to the nonuser.js table. And I want header to be same for both, content in textbox should not change when I switch between pages.
I'm new to next.js and react
header.js
import React, { Component } from 'react';
import '../Header/header.css';
import { Menu, Input, Icon } from 'antd';
import Link from 'next/link';
class HeaderComponent extends Component {
render() {
return (
<div className="navbar">
<div className="header">
<div className="col-1">
<div className="menu">
<div>
<Link href="/User"><a>Users</a></Link>
</div>
<div>
<Link href="/nonUser"><a>Non Users</a></Link>
</div>
<Input className="text-box" placeholder="Enter name" prefix={<Icon type="search" ></Icon>}></Input>
</div>
</div>
</div>
</div>
)
}
}
export default HeaderComponent
user.js
class User extends Component {
render() {
return (
<React.Fragment>
<div className="ant-table-row">
<div className="table-head-text">
<span className="text">Users({data.length})</span>
<Pagination defaultCurrent={1} total={100} />
</div>
<Table
rowKey={data._id}
columns={this.columns1}
rowSelection={this.rowSelection}
onExpand={this.onExpand}
dataSource={data} />
</div>
</React.Fragment>
)
}
I didn't add nonuser component, its same as user component
index.js
import Header from '../components/Header/header';
import Layout from '../components/Layout';
function App() {
return (
<Header/>
<div>
</div>
)
}
export default App;
I've done this, On first landing the only header is there and on clicking user link in header, header disappears and only table of user is shown.
EDIT:
I tried this header appears in both and I placed a textbox in header .textbox value clears when I switch between pages.
user.js and nonuser.js
render(){
return(
<Layout>
<div>.....</div>
</Layout>
)
}
Also tried
index.js
render() {
return (
<Layout>
<div>
</div>
</Layout>
)
}
layout.js
const Layout = ({children}) => (
<div>
<Header></Header>
{children}
</div>
);

From what I make of your question, you want to use HeaderComponent as a common header for both pages? Then I'd suggest placing it in your components/Layout file. Next will wrap all pages in the layout component, thus adding your header to all pages.
I'm also wondering why you have an index.js file? Unless it's placed in pages/ folder, it isn't something you normally do in Next. The pages user.js and nonuser.js should also be placed in the pages/ folder. Next will then automatically load the to files and provide them under the routes /user and /nonuser (based on the name of the file). This will also make Next wrap each page in the layout component mentioned above.
I'd suggest looking into NextJS learning guide. It provides a very good introduction to NextJS and will make it a lot easier to use NextJS if you. They have a lesson explaining how to use Shared Components which explains exactly what you seem to be looking for.
Hope this helps a bit.
Edit:
Example using _app.js
The following is an example of how to use a custom layout component in next using _app.js. It's based on Nexts own example.
// components/Layout.js
import React, { Component } from 'react';
import Header from './Header';
class Layout extends Component {
render () {
const { children } = this.props
return (
<div className='layout'>
<Header />
{children}
</div>
);
}
}
// pages/_app.js
import React from 'react';
import App from 'next/app';
import Layout from '../components/Layout';
export default class MyApp extends App {
render () {
const { Component, pageProps } = this.props
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
}
To get more information on how to make use of _app.js properly, check out their documentation on custom app.

Related

Workaround for Next.JS error "referenceError: document is not defined" for an external library component?

I am having some troubles integrating a component from the outside library 'react-calendly', the PopUpButton widget specifically, that requires the parent DOM node to be inserted into. My current understanding is that my issue is being caused by the fact that Next.js uses SSR and therefore I do not have access to the browser. How can I work around this? For reference, my website is a very simple fullstack app for his business and I am new to React/full-stack development. Here is the code for the app portion that renders my page components:
import '../styles/globals.css'
import styles from '../styles/App.module.css'
import Navbar from '../components/navbar'
import Footer from '../components/footer'
function MyApp({Component, pageProps}) {
return (
<div className={styles.app}>
<div>
<Navbar />
</div>
<div className={styles.body} id="body">
<Component props={pageProps} />
</div>
<div>
<Footer className={styles.footer}/>
</div>
</div>
)
}
export default MyApp
And here is the code for my specific page component:
import styles from '../styles/Home.module.css'
import Head from 'next/head'
import { PopupButton } from 'react-calendly'
export default function Home() {
return (
<div className="home">
<Head>
<title>Homepage</title>
</Head>
<div className="cal_div">
<PopupButton
url="https://calendly.com/my_url"
rootElement={document.getElementsById("body")}
text="Click here to schedule!"
/>
</div>
</div>
)
}

Is it possible to hide a parent component from child component in React.js?

As shown in the Flowchart (Flowchart), I want to hide the Header component if Main component renders the Login component. But if the Main component renders the Home component, I want to display the Header component.
This is App.js file:
import React from 'react'
import Header from 'Header'
import Main from 'Main'
import Footer from 'Footer'
function App() {
return (
<div className="App">
<Header />
<Main />
<Footer />
</div>
)
}
export default App;
This is Main.js file:
import React from 'react'
import Home from './Home'
import Login from './Login'
function Main() {
let user = true //Toggled by users
return (
<div>
{
user ? ( <Home /> ) : ( <Login /> )
}
</div>
)
}
export default Main
Putting the Header Component in Home itself will not solve the problem as I have to add much more pages and adding a Header component in every page doesn't seem efficient.
That's a use case of lifting the state up, here your user state should be in the scope of Header and Main.
Then just pass the user (isLogged in the example) to Main, via props or Context API.
function Main({ isLogged, toggleLogin }) {
return (
<div>
<button onClick={toggleLogin}>toggle</button>
{isLogged ? <>Home</> : <>Login</>}
</div>
);
}
function App() {
const [isLogged, toggle] = useReducer((p) => !p, false);
return (
<div className="App">
{!isLogged && <>Header</>}
<Main isLogged={isLogged} toggleLogin={toggle} />
<>Footer</>
</div>
);
}

How to send data from one component to another in nextjs

I'm working in nextjs.I have header component and in order to show header in all other pages ,overrided app.js with _app.js .Header has 2 navigation link usersList and users.
Now I want to send data from header component to another page say usersList and users on click of submit in header.How we can achieve that .
I know that we can use context .I'm using class based component don't know weather we can use context.
Is there any other solution to this problem..
Please help
header.js
class HeaderComponent extends Component {
onSearch(event){
//some code
}
render() {
return (
<div className="navbar">
<Input id="search-input" className="text-box" placeholder="Enter name or Email.." onKeyDown={($event)=>this.onSearch($event)} prefix={<Icon type="search" onClick={()=>this.onSearch} ></Icon>}></Input>
</div>
)
}
}
export default HeaderComponent
Layout.js
import React, { Component } from 'react';
import Header from './Header';
class Layout extends Component {
render () {
const { children } = this.props
return (
<div className='layout'>
<Header />
{children}
</div>
);
}
}
_app.js
import React from 'react';
import App from 'next/app';
import Layout from '../components/Layout';
export default class MyApp extends App {
render () {
const { Component, pageProps } = this.props
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
}
userList.js
class AppUser extends Component {
render() {
return (
<Table
rowKey={data._id}
columns={this.columns1}
onExpand={this.onExpand}
dataSource={data}
/>
)
}
}
EDIT :
can we achieve it through props
You can use ReactRedux to create a store and have it accessible from all components.
https://redux.js.org/api/store [1]

how can I dynamically attach sidebar components to multiple instances of sidebar?

I'm new to React and building out a design a ran into a problem.
I have a component called SideBar. I am using this component two times, one on each side of the page.
The problem is that I would like to add different components to each instance of the SideBar component. These would be lists of various items and etc. I assumed I could next component tags but the sidebar component doesn't output.
import React, { Component } from "react";
import SideBar from "./WorkspaceComponents/SideBar";
import ScrollerBox from "./WorkspaceComponents/SideBarComponents/ScrollerBox";
class Workspace extends Component {
render() {
return (
<main className="reely-workspace">
<SideBar position="SideBarLeft">
<ScrollerBox />
</SideBar>
<SideBar position="SideBarRight" />
</main>
);
}
}
export default Workspace;
Your sidebar component should receive a children prop and render it out.
Something like this:
class Sidebar extends Component {
render() {
const {children} = this.props;
return (
<div className="sidebar">
<h1>Sidebar</h1>
{children}
</div>
)
}
}
Check out this post on react docs to understand how to compose react components: https://reactjs.org/docs/composition-vs-inheritance.html
You can make your SideBar Component a wrapper component which wraps around the content given in it.
Making SideBar Component a Wrapper Component :
class Sidebar extends Component {
render() {
return (
<div className="sidebar">
// You can add any custom element here //
{this.props.children}
</div>
)
}
}
All your element passed inside the SideBar Component will now be rendered as a part of SideBar along with what it contains.
Way to consume the wrapper component:
<SideBar>
<Content1></Content1>
<Content2></Content2>
<Content3></Content3>
</SideBar>

An alternative to create a layout?

I want to create a layout containing the header and footer, with in middle every other component.
It will look something like this:
<Layout>
<Component1/>
<Component2/>
...
</Layout>
Technically I already achieved the desired outcome by using semantic ui react's Container and my code looks like this:
import React from 'react';
import { Container } from 'semantic-ui-react';
import Footer from './Footer';
import Header from './Head';
export default props => {
return (
<Container style={{width:'100%'}}>
<Header/>
<div style={{marginTop: '1%'}}>
{props.children}
</div>
<Footer />
</Container>
);
};
I would like to achieve the same result, but without using the Container offered by semantic-ui-react.
I tried in fact to remove <Container> but I am getting this error:
Line 9: Parsing error: Adjacent JSX elements must be wrapped in an
enclosing tag. Did you want a JSX fragment <>...?
If I remove completely the <div> tag I am getting another error:
Unexpected token, expected ","
I am not 100% sure but I understood that I should be using a class which expands the react component. I tried this which also failed:
class props extends React.Component {
render(){
return (
<Header/>
{props.children}
<Footer />
);
}
};
export default props;
You can remove <Container/>, but you will still need a parent component to wrap <Header/>, <Footer/>, and your content div, if you wish to keep the same markup. If, for semantic reasons, you don't want to use a div, use <React.Fragment/> as zfrisch mentioned
import React from 'react';
import { Container } from 'semantic-ui-react';
import Footer from './Footer';
import Header from './Head';
export default props => {
return (
<div style={{width:'100%'}}> // OR <React.Fragment/>
<Header/>
<div style={{marginTop: '1%'}}>
{props.children}
</div>
<Footer />
</div>
);
};

Resources