Main content wrapper best practices - html

I want to create a main content wrapper so I don't have to add classes to each component separately, I use tailwindCSS. It is just a couple of classes, mainly to give the content a margin, a max width and keep it centered.
I put a couple of divs encompasing the routes, but I don't know if this is considered a good practise.
Here is my App.jsx
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
// pages
import Navbar from './Navbar';
import Home from './Home';
import About from './About';
import Contact from './Contact';
function App() {
return (
<Router>
<div className='font-mono'>
<Navbar />
<div className='flex justify-center'>
<div className='m-10 lg:max-w-4xl'>
<Routes>
<Route path='/' element={<Home />}/>
<Route path='/about' element={<About />} />
<Route path='/contact' element={<Contact />} />
</Routes>
</div>
</div>
</div>
</Router>
);
}
export default App;

Yeah I imagine this is pretty common. I typically abstract it in a separate component.
/components/container/Container.js
export default function Container({ children }) {
return (
<div className='flex justify-center'>
<div className='m-10 lg:max-w-4xl'>{children}</div>
</div>
);
}
You can then import it and use it wherever you'd like. In the case of wrapping your routes I suppose you won't be reusing it elsewhere, but it does still remove some visual noise and keep things a little organized.
/App.js
import Container from './components/container/Container';
function App() {
return (
<Container>
<Router>
<Routes>
<Route path='/' element={<Home />}/>
<Route path='/about' element={<About />} />
<Route path='/contact' element={<Contact />} />
</Routes>
</Router>
</Container>
);
}

Related

Can we put html inside Route element?

<Router>
<Routes>
<Route path='/' element={<Navbar />} />
<Route path='/' element={<div className='recipes'>
{query ? query.map((object, i) => (
<RecipeCard
src={object.src}
ingredients={object.ingredients}
steps={object.steps}
key={i}
/>
)) : "Loading"}
</div>}/>
<Route path='/' element={<Details />} />
</Routes>
</Router>
For example in the above code, I want to render the HTML along with the Route element.
I am not getting the 2nd and 3rd Route tags displayed on my localhost. Where is my mistake?
What is the correct way to do this?
The only requirement is that the element prop takes a React.ReactNode. In other words, it takes any valid JSX.
The issue though is that there can only be one route per path. Your code is trying to render 3 routes on the same "/" path. Just unconditionally render the Navbar and Details components not on a route.
Example:
<Router>
<Navbar />
<Routes>
<Route
path='/'
element={(
<div className='recipes'>
{query
? query.map((object, i) => (
<RecipeCard
src={object.src}
ingredients={object.ingredients}
steps={object.steps}
key={i}
/>))
: "Loading"
}
</div>
)}
/>
</Routes>
<Details />
</Router>
If you are wanting to conditionally render Navbar and Details on only certain routes then create a layout route component.
Layout Route
Outlet
Example:
import { Outlet } from 'react-router-dom';
const Layout = () => (
<>
<Navbar />
<Outlet /> // <-- nested routes render element content here
<Details />
</>
);
Render the routes you want to have the navbar and details as nested routes, and for the routes you don't want them render these as sibling routes.
<Router>
<Routes>
<Route element={<Layout />}>
<Route
path='/'
element={(
<div className='recipes'>
{query
? query.map((object, i) => (
<RecipeCard
src={object.src}
ingredients={object.ingredients}
steps={object.steps}
key={i}
/>))
: "Loading"
}
</div>
}
/>
...other routes with Navbar and Details...
</Route>
...other routes w/o Navbar and Details...
</Routes>
</Router>

How can I put a class as a element parameter in react router?

function App() {
return (
<Router>
<Routes>
<Route path="/nav" element={Nav()}/>
<Route path="/page1" element={Page1()}/>
<Route path="/page2" element={Page2()}/>
<Route path="/map" element={Mapp()}/>
</Routes>
</Router>
);
}
The above is my function, which I render. nav, page1, and page2 all work fine since I wrote them as functions. However, the "Mapp" is a class. How can I make this work?
In react-router-dom v6 the Route component's element prop takes a ReactElement, i.e JSX. I suspect the Nav, Page, and Page2 function components work because they take no props and return JSX. If these are actually React components they should be passed as JSX. Same goes for class-based components, pass them as JSX.
function App() {
return (
<Router>
<Routes>
<Route path="/nav" element={<Nav />}/>
<Route path="/page1" element={<Page1 />}/>
<Route path="/page2" element={<Page2 />}/>
<Route path="/map" element={<Mapp />}/>
</Routes>
</Router>
);
}

Trouble migrating to react-router v4

I am having trouble migrating to react router 4 with nested routes. Here was some snippets from my previous code. was my layout container and everything was rendered within that if logged in (otherwise redirect to login)
ReactDOM.render(
<Provider store={ store }>
<div>
<Router history={ history }>
<Route path='/login' component={ Login } />
<Route path="/password/reset" component={PasswordReset} />
<Route path='/register' component={ Register } title={ 'Register' } />
<Route path='/password/change/:token' component={ ChangePassword } title={ 'Register' } />
<Route component={ EnsureLoggedInContainer }>
<Redirect from='/' to='/dashboard' />
<Route path='/' component={ App }>
<Route path='/logout' component={ Logout } />
....
</Router>
</div>
within to render the children components:
class ContentLayout extends React.Component {
constructor(props) {
super(props);
this.state = {};
}
render() {
let children = null;
if (this.props.children) {
children = React.cloneElement(this.props.children, {
updateHeader: this.props.updateHeader,
});
}
return (
<div className={ this.props.cls }>
<MainHeader
updateHeader={ this.props.updateHeader }
header={ this.props.header }
/>
{children}
</div>
);
}
}
With v4 I've been trying to figure out the proper way to render as the layout and any child components within. So far I've been trying to get it working but feel I am on wrong path. (Currently props.match always points to '/')
ReactDOM.render(
<Provider store={ store }>
<ConnectedRouter history={history}>
<div>
<Switch>
<Route exact path='/login' component={ Login } />
<Route exact path="/password/reset" component={PasswordReset} />
<Route exact path='/register' component={ Register } />
<Route exact path='/password/change/:token' component={ ChangePassword } />
<Route path='/' component={ App } />
</Switch>
</div>
</ConnectedRouter>
</Provider>,
document.getElementById('app')
);
Within App
const RouteWithProps = ({ component: Component, props, ...extraProps})=> {
return (<Route
{...extraProps}
render={() => <Component {...props} {...extraProps} />}
/>
);
}
and with the component rendering
{securedRoutes.map((route, i) => (
<RouteWithProps key={i} {...route} updateHeader={this.props.updateHeader} location={this.props.location} match={this.props.match} />
))}
What is the proper way or a good example of how to structure the app so for all logged in routes the layout is
<App>
<ContentLayout>
<Child>
with App passing props like updateHeader and anything else to all children.
I got it working by removing passing location and match to RouteWithProps.
I had an issue with the RouteWithSubRoutes example in dealing with nested routes for things like /.../:id and /.../:submit ended up doing this to make work so I can continue working. Do not think this is ideal but will work till another answer on best practices.
const RouteWithProps = ({ component: Component, ...extraProps }) => {
return (<Route exact path={extraProps.path}
{...extraProps}
render={matchProps => <Component {...matchProps} {...extraProps}
/>}
/>
);
}
Also removed passing this.props.location and match to this component.

Routing not working in reactjs application

I have created a reactjs app having three pages (components), App, Login and Register, where I need to navigate from page to page by entering the url in the browser but the navigation is not working for me. Entering any url just shows me the 'App' page.
following is the code that I have written in main.js file of the app and the url that I am using to navigate looks something like this http://localhost:8080/#/login or http://localhost:8080/#/reg
import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter as Router, Route, NavLink, Redirect, Switch, hashHistory} from 'react-router-dom'
import App from './../jsx/App.jsx';
import Login from './../jsx/Login.jsx';
import Register from './../jsx/Register.jsx';
ReactDOM.render((
<Router history={hashHistory}>
<div>
<Route path="/" component={App}/>
<Route path="/login" component={Login}/>
<Route path="/reg" component={Register}/>
</div>
</Router>
), document.getElementById('app'))
You need to configure the route to match the root path exactly. Try this...
<Route exact path="/" component={App}/>
Remove / from your path in Route path in
<Route path="/login" component={Login}/>
<Route path="/reg" component={Register}/>
try this it's working for me
entry class
import React from 'react';
import ReactDOM from 'react-dom';
import Layout from './Component/Layout.jsx';
import { Router, Route, IndexRoute, hashHistory } from "react-router";
import Archives from './Component/Archives.jsx';
import Settings from './Component/Settings.jsx';
import Featured from './Component/Featured.jsx';
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={Layout}>
//<IndexRoute component={Featured}></IndexRoute>
<Route path="archives" name="archives" component={Archives}></Route>
<Route path="settings" component={Settings}></Route>
<Route path="featured" component={Featured}></Route>
</Route>
</Router>,
document.getElementById('app'));
Layout class
{
render{
return(
<div>
{this.props.children}
<ul>
<li><Link to="archives">archives</Link></li>
<li><Link to="settings">settings</Link></li>
<li><Link to="featured">featured</Link></li>
</ul>
</div>
);
}
}
If you are using react router 4, then that looks fine. However, you can try using a as shown below:
<BrowserRouter>
<Switch>
<Route path="/" component={Home} />
</Switch>
</BrowserRouter>
This is in latest versions of react. The Home component is as below:
render() {
return (
<div>
<p>Header Section</p>
<Header/>
<p>Home component</p>
<Link to="/search">search</Link>
<Route path="/search" component={Search}/>
</div>
);
}
So most probably what you need to do is to just add a switch. Other solutions may be possible too. Hope this helps :)
Use BrowserRouter and Switch from 'react-router-dom'
if you use BrowserRouter no need to pass history as props as it handles itself.
Try this.
<Router>
<Switch>
<Route exact path="/" component={App}/>
<Route exact path="/login" component={Login}/>
<Route exact path="/reg" component={Register}/>
</Switch>
</Router>

React JS component with nested navigation

I've been having some trouble with the following. I've tried for a few hours to find some help through searching, but have come up empty handed. It could be that I don't know the name of what I'm trying to do, but I figured I'd ask here.
I've been learning React for about a month. Currently I'm trying to create a component which has it's own navigation bar and displays it's content based on which link in the component's navigation bar is clicked.
I have a Navigation bar for the entire website, using React Router, and I've tried nesting the component's route in the Route for the page I want it displayed, but when I click on a link within said component, instead of simply having the content displayed within that component, I'm navigated to a new page (in this case: localhost3000/#/project1). That new page displays the entire component, with the correct content. However, I want to avoid navigating to a new page.
Here's a pic of what I want to do.
Here's some of the code I've got so far. (I've omitted the imports and anything else unnecessary.
My index.js
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={OtherPage}></IndexRoute>
<Route path="Project_Page" component={ProjectPage} />
<Route component={ProjectsComponent}>
<Route path="project1" component={Project1} />
<Route path="project2" coponent={Project2} />
<Route path="project3" coponent={Project3} />
</Route>
<Route path="Another_Page" component={AnotherPage}></Route>
</Route>
</Router>
,
document.getElementById('root')
);
My ProjectPage.js
export default class ProjectPage extends Component{
render(){
return(
<div>
<ProjectsComponent />
</div>
);
}
}
My ProjectsComponent.js
export default class ProjectsComponent extends Component{
render(){
return(
<div>
<ProjectsNav /> // this is the navbar for my projects component
<div>
{this.props.children}
</div>
</div>
);
}
}
My ProjectsNav.js
export default class ProjectsNav extends Component{
render(){
return(
<div>
<Link to="Project1" className="btn btn-primary">Project 1</Link>
<Link to="Project2" className="btn btn-primary">Project 2</Link>
<Link to="Project3" className="btn btn-primary">Project 3</Link>
</div>
);
}
}
Finally
My Project1.js project2 && project3 are pretty much the same thing.
export default class Project1 extends Component{
render(){
return(
<div className="project">
Hello from Project 1
</div>
);
}
}
I'm sorry if this is something that's already been covered. If it has, please feel free to point me in the right direction. That's really all I need.
Thank you so much for your help.
ProjectsComponent component is not required, Try these components:
ReactDOM.render(
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={OtherPage}></IndexRoute>
<Route path="Project_Page" component={ProjectPage}>
//<Route component={ProjectsComponent}>
<IndexRoute path="Project_Page/Project1" component={Project1} />
<Route path="Project_Page/Project2" coponent={Project2} />
<Route path="Project_Page/Project3" coponent={Project3} />
</Route>
<Route path="Another_Page" component={AnotherPage}></Route>
</Route>
</Router>
,
document.getElementById('root')
);
export default class ProjectPage extends Component{
render(){
return(
<div>
<ProjectsNav />
<div>
{this.props.children}
</div>
</div>
);
}
}
export default class ProjectsNav extends Component{
render(){
return(
<div>
<Link to="Project_Page/Project1" className="btn btn-primary">Project 1</Link>
<Link to="Project_Page/Project2" className="btn btn-primary">Project 2</Link>
<Link to="Project_Page/Project3" className="btn btn-primary">Project 3</Link>
</div>
);
}
}
Let me know if u face any issue or want any help.