I am a beginner in ReactJS. I have been experiencing problems with the code below, which I have written:
class Navigation extends React.Component {
render() {
return (
<div>
<Router>
<button>
<Link to = "/home">Home</Link>
</button>
<button>
<Link to = "/portfolio">Portfolio</Link>
</button>
</Router>
</div>;
)
}
}
class Content extends React.Component {
render() {
return (
<React.Fragment>
<Router>
<Switch>
<Route exact path="/home">
<h1>Home</h1>
</Route>
<Route path="/portfolio">
<h1>Portfolio</h1>
</Route>
</Switch>
</Router>
</React.Fragment>;
)
}
}
class App extends React.Component {
render() {
var element = (
<div>
<Navigation />
<Content />
</div>;
)
return element;
}
}
ReactDOM.render(<App />, document.getElementById('root'));
Problem:
I would like the render() function of Content component to change every time a user clicks on a Link from the Navigation component. How can I go about doing this?
You don't to wrap your Navigation component with Router. As is only the links that will navigate to the component. And another thing is wrap your App component with main BrowserRouter which i guess you have imported as Router here.
class Navigation extends React.Component {
render() {
return (
<div>
<button>
<Link to = "/home">Home</Link>
</button>
<button>
<Link to = "/portfolio">Portfolio</Link>
</button>
</div>;
)
}
}
class Content extends React.Component {
render() {
return (
<React.Fragment>
<Switch>
<Route exact path="/home">
<h1>Home</h1>
</Route>
<Route path="/portfolio">
<h1>Portfolio</h1>
</Route>
</Switch>
</React.Fragment>;
)
}
}
class App extends React.Component {
render() {
return (<Router>
<Navigation />
<Content />
</Router>);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
Hope this works for you.
Related
This the js file where I have added my router and it contains all the route of my application
router. Below is the code of My App.js
export default class App extends Component {
static displayName = App.name;
render() {
return (
<Router>
<Layout />
<Switch>
<Route path='/employee' exact component={Employee} />
<Route path='/employer' component={Employer} />
<Route path='/addEmployer' component={AddEmployer} />
<Route path='/user' component={UserManagement} />
<Route path='/addUser' component={AddUser} />
</Switch>
</Router>
);
}
}
I have created the Layout page which contains my navbar component, sidebar component, main content and footer too.
Below is the code of Layout.js. I want my layout to be static across the application
import React, { Component } from 'react';
import { Container } from 'reactstrap';
import '../../css/main.css';
import { Navbar } from './Navbar';
import { Footer } from './Footer';
import { SideNavbar } from './SideNavbar';
export class Layout extends Component {
static displayName = Layout.name;
constructor(props) {
super(props);
}
render() {
return (
<div>
<Navbar />
<div id="layoutSidenav">
<SideNavbar />
<div id="layoutSidenav_content">
<main className="flex">
{this.props.children}
</main>
<Footer />
</div>
</div>
</div>
);
}
}
When I am routing the employer from url, the employer component is not rendering under main folder.
currently it is been rendering under the footer of the page. This causing an issue in makin my application as SPA.
Awaiting the response
Issue
Your Layout component looks to be designed to render the content as children, but in your App component you don't pass it any children. The Switch is rendered under/after Layout component.
class Layout extends Component {
static displayName = Layout.name;
constructor(props) {
super(props);
}
render() {
return (
<div>
<Navbar />
<div id="layoutSidenav">
<SideNavbar />
<div id="layoutSidenav_content">
<main className="flex">
{this.props.children} // <-- content
</main>
<Footer />
</div>
</div>
</div>
);
}
}
class App extends Component {
static displayName = App.name;
render() {
return (
<Router>
<Layout /> // <-- no children
<Switch>
<Route path='/employee' exact component={Employee} />
<Route path='/employer' component={Employer} />
<Route path='/addEmployer' component={AddEmployer} />
<Route path='/user' component={UserManagement} />
<Route path='/addUser' component={AddUser} />
</Switch>
</Router>
);
}
}
Solution
Wrap the Switch.
class App extends Component {
static displayName = App.name;
render() {
return (
<Router>
<Layout>
<Switch>
<Route path='/employee' exact component={Employee} />
<Route path='/employer' component={Employer} />
<Route path='/addEmployer' component={AddEmployer} />
<Route path='/user' component={UserManagement} />
<Route path='/addUser' component={AddUser} />
</Switch>
</Layout>
</Router>
);
}
}
Router needs to define where we wanted to render our component. Like In my case it should be under Layout component itself rather the defining at App.js part
I'm loading my adminDashboard component in app.js with Route. now in adminDashboard based on URL, I want to render some component. but, it's not loading any component. also, there is no activity on the network tab in chrome console.
if I render them without Route, they are rendering properly.
app.js
class App extends Component {
render() {
let { error, success } = this.props;
const Admin = Authorization(['admin'])
return (
<div className='app'>
<AdminNavbar logout={this.props.logout}/>
<Switch>
<Route exact path='/admin/signin' render={(props) => {
return <AuthForm />
}}
/>
<Route exact path='/admin' component={Admin(AdminDashboard)} />
</Switch>
<Footer />
</div>
);
}
}
MyComponent component
const MyDashboard = (props)=> ` this is dashboard`
Admindashboard
class AdminDashboard extends Component{
render() {
return (
<div>
<div className='row'>
<div className='col-md-2'>
<NavBar />
</div>
<div className='col-md-10'>
< Commisions /> //working properly if i load it without route
<Switch>
<Route exact path='/admin/dashboard' component={MyDashboard} /> // not work
//some other route
</Switch>
</div>
</div>
</div>
)
}
}
I have a root component which uses react-router:
<HashRouter>
<aside>
<Sidebar />
</aside>
<main>
<Switch>
{/* -- routes go here -- */}
</Switch>
</main>
</HashRouter>
I want my Sidebar component to have different content depending on which route we're on. So if I have two routes, foo and bar, when I go to /foo I want Sidebar to have different props than when I visit /bar. I've tried passing the location as a prop:
<Sidebar location={this.context.router.location.pathname} />
But I'm pretty sure that's not how it works... And sure enough it didn't work.
You can use withRouter to pass values from route to another component. This way you can do conditional rendering or implement any other logic related to the current route to your component.
You can get access to the history object’s properties and the closest
's match via the withRouter higher-order component. withRouter
will re-render its component every time the route changes with the
same props as render props: { match, location, history }.
Example (from official documentation)
// A simple component that shows the pathname of the current location
class ShowTheLocation extends React.Component {
static propTypes = {
match: PropTypes.object.isRequired,
location: PropTypes.object.isRequired,
history: PropTypes.object.isRequired
}
render() {
const { match, location, history } = this.props
return (
<div>You are now at {location.pathname}</div>
)
}
}
// Create a new component that is "connected" (to borrow redux
// terminology) to the router.
const ShowTheLocationWithRouter = withRouter(ShowTheLocation)
Here's a method using React Router's withRouter to 'connect' the <Sidebar /> component to the router.
With withRouter we create our <Sidebar /> component as normal, then 'connect' it like this:
//Sidebar
class Sidebar extends React.Component {
render() {
const { location } = this.props;
return (
<div>
<h1>Sidebar</h1>
<p>You are now at {this.props.location.pathname}</p>
</div>
)
}
}
const SidebarWithRouter = withRouter(Sidebar);
In the end we have a new <SidebarWithRouter /> component connected to the router so it has access to match, location, and history.
Unfortunately the code snippet won't work in Stackoverflow due to the history within the iframe, but here's the code, and a working Codepen.
let { BrowserRouter, Link, Route } = ReactRouterDOM;
let { Switch, withRouter } = ReactRouter;
let Router = BrowserRouter;
// App
class App extends React.Component {
render() {
return (
<Router>
<div className="container">
<ul>
<li>
<Link to="/">Home</Link>
</li>
<li>
<Link to="/about">About</Link>
</li>
</ul>
<hr />
<aside>
<SidebarWithRouter />
</aside>
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
</Switch>
</div>
</Router>
);
}
}
//Home
const Home = () => (
<div>
<h1>Home</h1>
<p>This is the Home Page.</p>
</div>
);
//About
const About = () => (
<div>
<h1>About</h1>
<p>This is about</p>
</div>
);
//Sidebar
class Sidebar extends React.Component {
render() {
const { location } = this.props;
return (
<div>
<h1>Sidebar</h1>
<p>You are now at {this.props.location.pathname}</p>
</div>
)
}
}
const SidebarWithRouter = withRouter(Sidebar);
ReactDOM.render(<App />, document.getElementById("app"));
I have a single page React app. I have a BaseLayout component which serves as the container for the app. BaseLayout displays the header and footer and also the content as shown below:
class App extends Component {
render() {
return (
<div>
<BaseLayout>
</BaseLayout>
</div>
);
}
}
BaseLayout
export default class BaseLayout extends Component {
render() {
return (
<div>
<NavBar />
{this.props.children}
<Footer />
</div>
)
}
}
index.js
ReactDOM.render(
<BrowserRouter>
<Switch>
<Route path="/page_one" component={PageOne} />
<Route path="/page_two" component={PageTwo} />
<Route path="/" component={App} />
</Switch>
</BrowserRouter>,
document.getElementById('root')
)
All the navigation is inside the navBar.js component.
navBar.js
export default class NavBar extends Component {
render() {
return (
<div className="nav-bar">
<button><Link to="/">Home</Link></button>
<button><Link to="/page_one">Page One</Link></button>
<button><Link to="/page_two">Page Two</Link></button>
</div>
)
}
}
pageOne.js and pageTwo.js
export default class PageOne extends Component {
constructor(props) {
super(props)
}
render() {
return (
<div>
<h1>Page One </h1>
</div>
);
}
}
The problem is that when I go to page_one or page_two URL it only shows the content of the component and not the navigation bar.
How can I make the navigation bar and footer visible on all the pages using react router and react framework?
UPDATE:
App.js
class App extends Component {
render() {
return (
<div>
<BaseLayout>
</BaseLayout>
</div>
);
}
}
export default App;
I changed my index.js to the following:
ReactDOM.render(
<BrowserRouter>
<Route path="/" component={App}>
<Switch>
<Route path="/page_one" component={PageOne} />
<Route path="/page_two" component={PageTwo} />
</Switch>
</Route>
</BrowserRouter>,
document.getElementById('root')
)
Now, I get the following:
And the page does not go anywhere if I use the above code:
I think you should "lift" the App as the root Route.
By the way, Is App the same as BaseLayout? hard to tell from your example.
Example:
const Index = () => {
return (
<BrowserRouter>
<div>
<Route component={App} />
<Switch>
<Route path="/page_one" component={PageOne} />
<Route path="/page_two" component={PageTwo} />
</Switch>
</div>
</BrowserRouter>
);
};
A running code example, i'm not using a stack snippet as i can't use react-route with push state here.
I'm posting the entire code in case the url will be broken in the future:
import React from "react";
import { render } from "react-dom";
import { BrowserRouter, Route, Link, Switch } from "react-router-dom";
const Footer = () => <div>Footer...</div>;
class BaseLayout extends React.Component {
render() {
return (
<div>
<NavBar />
{this.props.children}
<hr/>
<Footer />
</div>
);
}
}
class NavBar extends React.Component {
render() {
return (
<div className="nav-bar">
<button>
<Link to="/">Home</Link>
</button>
<button>
<Link to="/page_one">Page One</Link>
</button>
<button>
<Link to="/page_two">Page Two</Link>
</button>
</div>
);
}
}
const PageOne = () => <h1>Page One</h1>;
const PageTwo = () => <h1>Page Two</h1>;
class App extends React.Component {
render() {
return (
<div>
<BaseLayout>{this.props.children}</BaseLayout>
</div>
);
}
}
const Index = () => {
return (
<BrowserRouter>
<div>
<Route component={App} />
<Switch>
<Route path="/page_one" component={PageOne} />
<Route path="/page_two" component={PageTwo} />
</Switch>
</div>
</BrowserRouter>
);
};
render(<Index />, document.getElementById("root"));
I am rendering a Home component inside a Route so that I can pass state in as a prop to the component.
class App extends React.Component {
constructor(props){
super(props)
this.state = {
page: 'false'
};
}
render() {
return (
<Router>
<div>
<Switch>
<Route exact path='/' render={()=><Home page={this.state.page}/>} />
<Route exact path='/projects' component={Projects} />
<Route render={function(){
return <p>Not Found</p>
}} />
</Switch>
</div>
</Router>
)
}
}
Inside the Home component, I want to trigger a route change from a function. Because the Component is rendered inside the Route the history prop doesn't get passed in and therefore I cannot trigger a route change like so:
class Home extends React.Component{
constructor(props){
super(props);
this.gotoProjects = this.gotoProjects.bind(this);
}
gotoProjects() {
this.props.history.push('/projects');
}
render() {
return (
<button onClick={this.gotoProjects.bind(this)}>Projects</button>
)
}
}
How can I change routes from a component while still retaining it's props?
UPDATE
I've created a History.js using createBrowserHistory
import { createBrowserHistory } from 'history'
export default createBrowserHistory()
And updated App.js to be
import history from '../history';
class App extends React.Component {
constructor(props){
super(props)
this.state = {
page: 'false'
};
}
render() {
return (
<Router>
<div>
<Switch>
<Route exact path='/' render={()=><Home history={history} page={this.state.page}/>} />
<Route exact path='/projects' component={Projects} />
<Route render={function(){
return <p>Not Found</p>
}} />
</Switch>
</div>
</Router>
)
}
}
So now when I click the button in Home the url goes to /projects but the view is still rendering Home instead of Projects. How do I render Projects after the history.push happens?