Say I have the following App.js:
App.js
render() {
return (
<div>
<Navbar />
<Router>
<Home path="/" />
<RouteA path="/routeA" />
<RouteB path="/routeB" />
</Router>
</div>
);
}
So I need the <Navbar /> to behave and look differently in the /routeA and /routeB.
For example, there is a back button in the <Navbar />. And when user is in /routeA, clicking the back btn will go back one step in history.
However, when user is in /routeB, not only that clicking back btn will now pops up an alert, we also need to render a component that has updating props inside the <Navbar />.
So the way I go about this is, well, redux: The <Navbar /> is connected to its own slice of state in the store. Then, in my routes, in order to make the navbar dynamic accordingly, I dispatch actions with my function and component to make the <Navbar /> behave and look the way I want. So far so good.
Problem is we can't serialize 'function' and 'component' objects in the store and subsequently localstorage...so like on refresh, they are gone...
So my workaround for the 'function' is I immediately dispatch it in the routes' constructor. Whereas for the 'component', I use Portal in my routes' render method to insert it to my <Navbar />...
My question is how would you implement this differently?
Thank you for reading!
You can send function to route components and call this funciton when component is mounted, you can have functions defined inside NavBar component, and switch based on the page you are on.
updateLayout = (page) => {this.setState({currentPage: page})}
render() {
return (
<div>
<Navbar currentPage={this.state.currentPage} />
<Router>
<Home path="/" render={()=> <ComponentHome updateLayout={this.updateLayout}>} />
<RouteA path="/routeA" render={()=> <ComponentA updateLayout={this.updateLayout}>} />
<RouteB path="/routeB" render={()=> <ComponentB updateLayout={this.updateLayout}>} />
</Router>
</div>
);
}
Related
I am using the react router to create multiple webpages without changing my navbar and all it gives me is a blank page. I have tried multiple things such as a browser router, and switch and neither of them work.
function App() {
return (
<div className="App">
<Navbar />
<Router>
<Link to="/">Home</Link>
<Link to="/aggrid">Aggrid</Link>
<Route path="/" component={GhibliModal} />
<Route path="/aggrid" component={Aggrid} />
</Router>
</div>
);
}```
Well first things first, you need to wrap your whole App component with <BrowserRouter>, but I from what you said in the question, I would assume you already know that.
Secondly, you don't need the <Router> component. Read here.
From reading the documentation, all <Route> components must be wrapped in a <Routes> (note the 's' at the end) component.
And lastly, I'm pretty sure you cannot have <Link> components inside the <Routes> component.
Also, the component prop is now called element, so
<Route path="/" component={GhibliModal} />
should become
<Route path="/" element={<GhibliModal/>} />
You need to add <Outlet /> tag in the components that are loaded by Router.
I usually put it at the end of the JSX:
return (
<div>
<yourcodehere/>
<Outlet/>
</div>
)
I'm building two form components and I want to display a two buttons onPage load, where the click on the first button takes to the first form or the click on the second button takes to the second form component. I've tried to use useNavigate/useHistory but i'm still on same page.
function App() {
const navigate = useNavigate()
return (
<div className="app">
<Header />
<button onClick={()=> navigate("/main")}>Click me!</button>
<button onClick={()=> navigate("/main2")}>Click me!</button>
<Routes>
<Route exact path="/main" component={Main}/>
<Route exact path="/main2" component={Main2}/>
</Routes>
</div>
);
}
export default App;
How can I use react-router or state to display the component when a each button is clicked? I would appreciate any help
Assuming that you have react-router-dom v6 since you have used <Routes></Routes>. You must write the code in the following manner under the assumption that you have included <Router> to wrap your application in index.js.
function App() {
const navigate = useNavigate()
return (
<div className="app">
<Header />
<button onClick={()=> navigate("/main")}>Click me!</button>
<button onClick={()=> navigate("/main2")}>Click me!</button>
<Routes>
<Route path="/main" element={<Main />}/>
<Route path="/main2" element={<Main2 />}/>
</Routes>
</div>
);
}
export default App;
Here, after clicking the first button, it will route you to /main which will serve the <Main /> component. The second button will route to /main2 and will serve the <Main2 /> component.
In version 6, there is no longer the need to write exact since the default behavior is to match the exact route. Also there are some interface changes where the component attribute is changed to element and it now takes the JSX as value and not the object itself.
I am creating an application using ReactJS. I am using react router v4 from react-router-dom.
I have written routes in index.js file.
<BrowserRouter>
<Switch>
<Route exact path="/" component={Login} />
<Route exact path='/dashboard' component={Viewport} />
</Switch>
</BrowserRouter>
Rest of the application in Viewport.js file.
return (
<div className="">
<Sidebar navigation={this.viewport} />
<HeaderBanner user={this.props.user} />
<div className="center-panel">
//todo
//Can I use router here?
</div>
</div>
)
After user login's, I am rendering Viewport which contains Sidebar and header bar by default. Based on the item click in the sidebar navigation, I need to render components dynamically. As of now, if I write anything in the place of todo, it renders only that component for the complete browser window.
Is there any way to use routers in multiple places of the application? If yes, how can I implement it? If no, what's the best solution?
As far as I have seen, routers will be stacked at one place in the application.
Thanks in advance.
I followed a tutorial on youtube recently which was very useful
So I took some of it and applied it to your setup
<BrowserRouter>
<div>
<Route exact path="/" component={Login} />
<Route exact path='/dashboard' component={Viewport} />
</div>
</BrowserRouter>
import { NavLink, Route } from 'react-router-dom';
class Viewport extends Component {
constructor(props) {
super(props);
}
render() {
return (
<div>
<div className="Side-bar">
<NavLink
activeClassName="active"
to={`${this.props.match.url}/sub-page-name-1`}>Sub Page 1</NavLink>
<NavLink
activeClassName="active"
to={`${this.props.match.url}/sub-page-name-2`}>Sub Page 2</NavLink>
<NavLink
activeClassName="active"
to={`${this.props.match.url}/sub-page-name-3`}>Sub Page 3</NavLink>
</div>
<HeaderBanner user={this.props.user} />
<div className="center-panel">
<Route path={`${this.props.match.url}/sub-page-name-1`} component={SubPagePanel1} />
<Route path={`${this.props.match.url}/sub-page-name-2`} component={SubPagePanel2} />
<Route path={`${this.props.match.url}/sub-page-name-3`} component={SubPagePanel3} />
</div>
</div>
)
}
}
I removed Switch as well because I didn't use it for my sub pages... :-S
Update: Have created a repo showing a working example of sub page content
https://github.com/PocketNinjaDesign/so-sub-routes-answer
Yes you can use <Routes> in as many places as you want. <Router> components are the ones you can only use once.
I have an <App/> component which renders for any page on my site:
const App = () => (
<div>
<Header />
<Main />
<Footer />
<Subfooter />
<SubfooterLegal />
</div>
)
export default App;
The problem I'm having now is that I have a Component (page) which doesn't include any of the components within <App /> aside from <Main /> (which is the router).
I'm puzzled on how to do this, since App.js is the parent component of all components. My only idea of how to do this (possibly) is that when a user clicks a <Link /> to the aforementioned component, I could add setState (maybe?) to App.js and change it to something like hideAppComponents = true and then hide the appropriate components. I know that in this case I would have to make <App /> extends Component since it would then be stateful.
Are there any suggested approaches for a use case like this?
As far as answering your specific question: Yes, adding state to your App and then rendering differently depending on the page would work.
However, a small refactoring of your components would make your problem easier.
In my opinion, a good use of <app> within the context of routing is to just use it to reference which route the user will be on.
<app>
<main>
<Switch>
<Route exact path='/' component={Home}/>
<Route exact path='/about' component={AboutUs}/>
<Route path='/somePageWithoutAFooter' component={CoolPage}/>
</Switch>
</main>
</app>
Now, you have set just a very set of minimal constraints from your top-level app. Depending on the route, you will render a specific child component. So this solves your direct problem. Now you can have CoolPage be its own custom thing, but then the Home page can do something else.
So far, so good. However lets say that both Home and AboutUs have the same basic template of the header and the subfooter that you've been talking about. It would be unfortunate for both of these components to have to describe this architecture inside the render. Instead, you could make a container component like this:
class MyLayout extends Component {
render() {
<div>
<Header />
{this.props.children}
<Footer />
<Subfooter />
<SubfooterLegal />
</div>
}
}
And this component can be used like this:
<MyLayout><Home></MyLayout>
So now, all you need to do is to wrap all of your normal pages in a MyLayout. This can either be done in the app itself, or in a child if it gets more complicated.
Edit: This example uses react-router since this post was tagged with it. You can follow the same principles without using the router if you want. It just makes the <Route> stuff easier to manage.
the only possible solution i can think other than your solution is to use loaction prop. Below is the sample code you can try.
import STORE from './store/STORE';
import {Provider} from 'react-redux';
import {Route, Router} from 'react-router-dom';
import createHashHistory from 'history/createHashHistory';
const history = createHashHistory();
render(
<Provider store={STORE}>
<Router history={history}>
<Route path="/" component={App}/>
</Router>
</Provider>, document.getElementById('app')
);
const App = (location) => (
location.pathname.includes("error") ?
<div>
<Main />
</div> :
<div>
<Header />
<Main />
<Footer />
<Subfooter />
<SubfooterLegal />
</div>
)
export default App;
I have an app which has a navbar, and a display below that shows all the posts.
Here is how it is setup:
var routes = (
<Router history={createHistory()}>
<Route path="/" component={App}>
<Route path="/submit" component={CreatePost}/>
</Route>
<Route path="*" component={NotExist}/>
</Router>
)
So, if you click on "New" in the navbar, you will be taken to server/submit and a form will appear where you can enter details for a new post. On submit, it will add the details to the posts state object.
Inside of App, I have a function called addToPosts().
render : function() {
//<CreatePost addPostToPosts={this.addPostToPosts} posts={this.state.posts}/>
return (
<div>
<NavigationBar/>
{this.props.children}
<DisplayPosts postData={this.state.posts} />
</div>
)
}
#kirill-fuchs yesterday told me to use {this.props.children} to send the properties. However, when I check react console, I see that props are empty. But, I know it is doing something because if I get rid of the {this.props.children} then clicking on New doesn't do anything. But when I put it back, it redirects to the form.
In addition, when I click submit in the form, it says this.props.addToPosts is not a function, because the props are empty.
Can someone please help me?
It sounds like you want to pass props down to the children. You can use the following to do that:
{React.cloneElement(this.props.children, {addToPosts: this.addPostToPosts, posts: this.state.posts})}
This will pass a prop into the CreatePost component that you can then call when the submit button is pressed.