Having troubles with react-semantic-ui and router - javascript

so heres the sample:
simple menu/header JSX:
<Menu fixed='top' inverted>
<Container>
<Menu.Item header>Simple Blog</Menu.Item>
<Menu.Item name='home' as={Link} to='/'
active={this.state.activeItem === 'home'}
onClick={this.handleItemClick}>Home</Menu.Item>
<Menu.Item name='create-p' as={Link} to='/create-post'
active={this.state.activeItem === 'create-p'}
onClick={this.handleItemClick}>Create post</Menu.Item>
</Container>
</Menu>
then I have basic index.js:
ReactDOM.render(
<Provider store={createStoreWithMiddleware(reducers)}>
<BrowserRouter>
<div>
<ApplicationMenu/>
<Container style={{marginTop: '5em'}}>
<Route exact path="/" component={Posts}/>
<Route exact path="/home" component={CreatePost}/>
</Container>
</div>
</BrowserRouter>
</Provider>
, document.querySelector('.start'));
It renders and looks fine. When I click one of menu items I can see the URL changing, but no action is taken besides that. Router does not render new component. If I select the changed URL and click enter, it renders the proper one, but it looks like it does not react on url changes provoked by semantic ui component.
For debug purposes I prototyped these menu items just using clean html and css (pure sui, not react one) and it worked.
Did anyone have have similar problems and managed to figure it out?
Thanks for any answer.

This is a common problem to react-router-dom.
React works the way that it rerenders everytime either:
the properties of a component change
the internal state changes
If you change the URL of the page, you do not trigger a rerender of that component. Therefore, your index.js won't be rerendered.
A simple solution to this problem is to wrap your Component with a withRouter.
So your new index should look like this:
import { withRouter } from 'react-router-dom';
ReactDOM.render(withRouter(
<Provider store={createStoreWithMiddleware(reducers)}>
<BrowserRouter>
<div>
<ApplicationMenu/>
<Container style={{marginTop: '5em'}}>
<Route exact path="/" component={Posts}/>
<Route exact path="/home" component={CreatePost}/>
</Container>
</div>
</BrowserRouter>
</Provider>)
, document.querySelector('.start'));
Now when the URL changes, the higher order component "withRouter" notices it and rerenders the component in it, so your correct component will be rendered.
As documented here: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/guides/blocked-updates.md
If you want to know more about the problem, read this GitHub issue: https://github.com/ReactTraining/react-router/issues/5037

Your Route path don't match your Item Link to.
Try changing your routes to:
<Switch>
<Redirect exact path="/" to="/home">
<Route exact path="/home/" component={Posts}/>
<Route exact path="/create-post/" component={CreatePost}/>
</Switch>
BTW: Take a look at react-router's <NavLink> to use instead of <Link> for your Navbar items.

Related

how to render pages on dashboard in react using material Ui

I am facing little bit difficulty, I have to manage my dashboard using material-UI with other components
the process of application is that first I want to open login foam and then the dashboard and I am willing to change just the right-center part of the dashboard with the different component by selecting the listItem option
here is my Dashboard
here is all routes defined on my App.js
<Provider store={store}>
<BrowserRouter>
< Routes>
<Route exact path='/' element={<Login/>} />
<Route exact path='/dashboard' element={<Dashboard/>} />
<Route exact path='/product' element={<Product/>}/>
</Routes>
</BrowserRouter>
</Provider>
currently, the issue is that when I am going to login which is on my "/" route and after the authentication the app navigate on the dashboard but when I click my product tab so the dashboard is disappear there
here is my product page
i am willing to that all pages should to render just in text area where text is showing
I will make some assumptions before answering your question:
You want the Dashboard view to be always available
The Dashboard view's white screen should receive different content depending on the route that you're currently in
In your app you should have some sort of Layout which wraps the entire App. You are using react-router v6 so most probably the way to go it will be this:
<Provider store={store}>
<BrowserRouter>
<Routes>
<Route path="/" element={<Layout />}>
<Route exact path='/login' element={<Login/>} />
<Route exact path='/dashboard' element={<Dashboard/>} />
<Route exact path='/product' element={<Product/>}/>
</Route>
</Routes>
</BrowserRouter>
</Provider>
And in your Layout component, something like this:
import { Outlet } from 'react-router-dom';
const Layout = () => (
<main>
<Outlet />
</main>
);
You can check the react-router documentation for <Outlet />
Did it help?
EDIT: Forgot to say that yout <Layout /> view should have the Drawer that you're showing in your first screenshot, and the white space is where Outlet should be.

React Router DOM is rendering 2 components

This is my router structure:
<Router>
<main className="py-3">
<Switch>
<Container>
<Route exact path="/admin" component={AdminScreen}></Route>
<Route path="/:campaignId" component={CampaignScreen}></Route>
<Route path="/" component={HomeScreen} exact></Route>
</Container>
</Switch>
</main>
</Router>
For "some" reason, when I go to /admin i also get the CampaignScreen rendered.
I added the <Switch> as you can see, but it does not seem to help.
Where lies the problem?
Since admin can theoretically also be a campaignId react router thinks it matches both routes, and you have the <Container> element directly inside the Switch it still renders both, the solution is to have your routes directly in the Switch

Navigating between multiple params - React js

So I've been working on a project lately using React js (I thought it would be similar to React native), while I pretty much understand most of it as I previously worked with React native a lot. There are still some new things I'm learning for example the react-router-dom npm. So I understand the basics and how it works, but I'm trying to use parameters which change depending on the user (User ID).
The code below shows how I'm currently using my router. While going to home (/) and /user/:id works, I can't go to /user/:id/settings. If I try going to the settings it renders both the /user/:id page and below it renders settings page.
What I want to be able to do is if the user is in the user/:id page they can click a button which takes them to the user/:id/settings instead of the current issue where it renders the setting page below the user page.
App.jsx
export class App extends React.Component {
render() {
return (
<Router>
<Route exact path="/" component={Home} />
<Route path="/user/:id" component={User} />
<Route path="/user/:id/settings" component={Setting} />
</Router>
)
}
};
User.jsx
render() {
return (
<div>
{/* Cool information about the user */}
<div
className="optionContent"
onClick={() => {
let uri = `/user/${this.props.match.params.id}/settings`;
this.props.history.push(uri)
}}
>
Press me
</div>
</div>
);
}
Extra information:
I have tried using variable parameters for users but I wasn't able to full make those work as once the user enters /user/:id page the buttons update the url but not the parameters in this.
I need to have the ID within the url to fetch from the API and some other stuff
Variable url: /user/:id/:type?
This is because with React Router v5 which is currently the latest version as v6 is completed, the routes aren't exact by default which means that for each of the routes, if the current route starts with the route of a component, this component will be displayed.
For your example:
<Router>
<Route exact path="/" component={Home} />
<Route path="/user/:id" component={User} />
<Route path="/user/:id/settings" component={Setting} />
</Router>
If the current route is "/user/user1" then it only matches the User component.
If the current route is "/user/user1/settings/ then it matches User and Settings components so they will both be rendered as you are finding.
To fix it, simply use the exact keyword on the component with the fewer requirements.
<Router>
<Route exact path="/" component={Home} />
<Route exact path="/user/:id" component={User} />
<Route path="/user/:id/settings" component={Setting} />
</Router>

React route does not getting displayed without click

I want to use react router for the navigation of my app. It is an electron desktop app, so my debugging is limited. When the login goes (which runs without routers) a component with a router gets displayed, but when this component gets displayed, it does not display the exact route "/". Only if I click the "Link" component it gets displayed. I am using the BrowserRouter Component. Does anyone have an idea?
That's the parent components render method:
render() {
return (
<Router>
<div style={styles.text}>
<AppBar title={this.state.title}/>
<Grid container className='mainGrid'>
<Grid item>
<Route exact path="/" component={Feed} />
</Grid>
</Grid>
<BottomNav/>
<Sidenav/>
</div>
</Router>
);
}
Thats the BottomNav render method:
render() {
const {value} = this.state;
return (
<BottomNavigation className='BottomNav' showLabels value={value}
onChange={this.handleChange}>
<BottomNavigationAction component={Link} to="/" label="Feed" icon={<BookIcon/>}/>
<BottomNavigationAction component={Link} to="/calendar" label="Calendar" icon={<CalendarIcon/>}/>
<BottomNavigationAction component={Link} to="/mail" label="Mail" icon={<MailIcon/>}/>
<BottomNavigationAction component={Link} to="/tickets" label="Tickets" icon={<AssignmentIcon/>}/>
</BottomNavigation>)
}
And that's the Feed components render method:
render(){
return(
<h1>Hallo Welt (Feed)</h1>
)
}
If you need more information, please write a comment.
You are missing the surrounding Switch component which renders the first Route that matches automatically.
<Switch>
<Route exact path="/" component={Feed} />
</Switch>
Edit
It seems that the initial route of your location is an empty string and not /. I never encountered this behavior, so it might be server related?
I can think of these two solutions:
Add a redirect
Add a <Redirect from="" to="/" /> in your App.jsx. This will force a forward slash in your path.
Disable Route strict mode
React router has added an exact prop for issues with a trailing slash. Although, I'm not 100% sure this will work in your example.
<Route exact path="/" component={Feed} exact={false} />

React router remounts children while changing routes (without reconciliation)

I have a situation where few routes consists of the same component and I want to preserve its state, but with this behavior it's fairly impossible.
Live example (look at seconds elapsed):
https://csb-43lp1km647-nkiinaibit.now.sh
CodeSandbox:
https://codesandbox.io/s/43lp1km647
Of course I could save and restore state of timer while changing routes, but my app has an infinite CSS transition as a background (not on every route).
I was trying adding keys, even portal, but it still remounts everything.
Is there any way to enforce typical React's reconciliation (remount only elements that have to be remounted)?
Update:
Just found out that <Switch /> will render everything until it finds element that matches, and that could be either a certain <Route /> or any element except it's inside <Fragment />.
Code:
<Router history={history}>
<Switch>
<Route path="/third" component={RouteWithoutTimer} />
<React.Fragment>
<Timer />
<Route exact path="/" component={FirstRoute} />
<Route path="/second" component={SecondRoute} />
</React.Fragment>
</Switch>
</Router>
Or with wildcard route:
<Router history={history}>
<Switch>
<Route path="/third" component={RouteWithoutTimer} />
<React.Fragment>
<Timer />
<Switch>
<Route exact path="/" component={FirstRoute} />
<Route component={NotFoundRoute} />
</Switch>
</React.Fragment>
</Switch>
</Router>
It's not a solution I was looking for, but it works fine.
You are mounting a new instance of Timer in each route.
If you want to share a component across routes, you should lift it to the parent component of the routes:
<React.Fragment>
<Timer />
<Switch>
<Route exact path="/" component={FirstRoute} />
<Route path="/second" component={SecondRoute} />
</Switch>
</React.Fragment>
This is where the state management libraries come to scene.
In React, states are per component and has lifecycle of it's owned component, so when router destructs/remounts the component, you lose all the data. I advice you to migrate your state to a state management library like redux as soon as possible. Otherwise your code can be mess if this is a medium-sized application.

Categories