An alternative to create a layout? - reactjs

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>
);
};

Related

ReactJS error is "This component must be used inside a <RecoilRoot> component."

But I'm twisting it slightly, where I don't have a layout but rather a per page component that I'd like to add to the header.
I am getting the following error:
Account.jsx looks something like this:
import { useRecoilValue } from "recoil";
import { userProfile } from "../../../recoil";
export default function Account() {
const profile = useRecoilValue(userProfile);
return (
<div className="w-screen h-full ">
<header>
<Navbar profile={dataMe} />
</header>
<main className="h-screen relative">
<div className='h-screen flex bg-gray-bg my-15 static'>
<div className='w-full mt-10 m-auto bg-white rounded-lg border'>
<div>
<div>
<dataMe />
</div>
<DetailAccount />
</div>
</div>
</div>
</main>
</div >
);
};
To use Recoil (A state management library for React) properly You have to add RecoilRoot wrap component(s). As we can read in documentation :
Components that use recoil state need RecoilRoot to appear somewhere
in the parent tree.
A good place to put this is in your root component
Example from official docs
import React from 'react';
import Account from './Account.jsx';
import {
RecoilRoot,
atom,
selector,
useRecoilState,
useRecoilValue,
} from 'recoil';
function App() {
return (
<RecoilRoot>
<ComponentsThatUseRecoilState />
{/* in Your case <Account /> component */}
</RecoilRoot>
);
}
You have to wrap your component(s) inside the RecoilRoot if you want the component to be using the Recoil functionality. As of documentations: https://recoiljs.org/docs/api-reference/core/RecoilRoot/
So you have to wrap your code inside <RecoilRoot> before you can use the useRecoilValue hook.
Example:
import {RecoilRoot} from 'recoil';
function AppRoot() {
return (
<RecoilRoot>
<ComponentThatUsesRecoil />
</RecoilRoot>
);
}
It's recommended to use this on root (App.tsx or what ever your root element is called) so all your other components can use the Recoil hooks as intended without having to wrap your components in a RecoilRoot every single time.

Target container is not a DOM element - error in importing a function

I'm a newbie here so apologies for what might be a very elemental question.
I am trying to fiddle with different ways to import components in React by following a tutorial but I can't seem to make it work. There must be a simple tweak that I am sorely missing.
I am trying to create export a component (Person2) to another JS (App)
Person2.js
import React from 'react'
import ReactDOM from 'react-dom'
function Person2(){
return (
<div>
<h1>Millie</h1>
<p>PERSON 2</p>
</div>
);
}
/*
ReactDOM.render(
<div>
<h1>Hello World!</h1>
</div>,
document.getElementById('#p2')
);
*/
//ReactDOM.render(<Person2 />, document.getElementById('App'));
ReactDOM.render(<Person2 />, document.querySelector('#p2'));
App.js
import React from 'react';
import './css/App.css';
import './css/w3.css'
import Person from './Person'; // Import a component from another file using class with default export
import './Person2'; // Import a a component from another file using ReactDom.render
function App() {
return (
<div className="App">
<header className="App-header">
<p>this is the header</p>
</header>
<body>
<div class="w3-row">
<Person name="Max" age="28"/>
<Person name="Ann" age="18"/>
<div id = "p2"></div>
</div>
</body>
</div>
);
}
export default App;
Any idea where I went wrong?
I'm getting an error "Error: Target container is not a DOM element."
ReactDOM.render is usually used only for rendering your root component, I don't think you should use it in that case. With that said, the problem is the order the code is executed. You try to render your Person2 component in a node that hasn't been yet rendered, thus you get that error
Unless you have a very strange use case, you should be using export not ReactDOM.render for this example.
In Person2, change to this:
//ReactDOM.render(<Person2 />, document.querySelector('#p2'));
export default Person2;
Then to use it, in App change to this:
import Person2 from './Person2'; // for default export
...
<Person name="Ann" age="18"/>
//<div id = "p2"></div> *** remove this ***
<Person2 /> // Use like this
If for whatever reason your app requires the use of ReactDOM.render here, I'd add a check for safety to make sure the element exists first.
if (!!document.getElementById('p2')) {
ReactDOM.render(<Person2/>, document.getElementById('p2'));
}

Have a common header layout in nextjs

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.

how to change the menu depending on the width of the screen?

I apologize for my English using a translator.
I use React.js.
I have a component "header" that accepts two other components - and .
import React, { Component } from 'react';
import styles from './Header.module.css';
import MainLogo from '../MainLogo/MainLogo';
import NavMenu from '../NavMenu/NavMenu';
import BurgerButton from '../BurgerMenu/BurgerButton';
import BurgerMenu from '../BurgerMenu/BurgerMenu';class Header extends Component {
render() {
return (
<header className={styles.header}>
<nav className={styles.navBar}>
<MainLogo />
<NavMenu />
</nav>
</header>
);
}
}
export default Header;
I also created a separate component .
I want to get this markup option: if the screen size is <= 420px, the component should be rendered in the header. With a screen width >420px, the component should be displayed.
I understand that the question is very banal, but I have not yet found an elegant solution.
Thank you in advance!
P.S. using an external library is not suitable.
You can use react-media to render components conditionally based on the screen's size.
In your case, it would look something like this (adapt for your specific markup)
<header className={styles.header}>
<nav className={styles.navBar}>
<MainLogo />
<NavMenu />
<Media query={{ maxWidth: 420 }}>
{matches => <MyComponent /> // Component is in the header}
</Media>
</nav>
</header>
<Media query={{ minWidth: 421 }}>
{matches => <MyComponent /> // Component is outside of the header}
</Media>

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>

Resources