I have a question, I will appreciate if you could help me. I was building a simple react movie app, using redux for manage the state. I also use react router dom for manage basic routes.
I have the home page, where I render some radio buttons that when clicked they dispatch an action to filter the movies by a genre.
So my question is that when I clicked in a radio button it made the filter but the radio button it not checked.
Whereas if I put the Home component outside the Route it do it well, the radio button is checked and it filter the movies list.
This is the app component, with the home outside the router working well and the home inside the routing.
<Home props={props}/>
<Switch>
<Route exact path='/home' component={() => <Home props={props}/>} />
<Route path='/genre=:genre' component={detailGenre} />
<Redirect to='/home' />
</Switch>
This is the radio button
const handleRadioButtons = (e) => {
sortMovies(e.target.value)
}
...
<label htmlFor='horror'>Horror</label>
<input onChange={handleRadioButtons} name='filmtype' value='horror' type='radio' id='horror' />
I'm sure i'm not understanding some behaviour or maybe i'm missing something.
Thanks in advance.
Why is this happening and how can I solve it ?
The component prop tells React Router to generate the component using React.createElement, and if you pass it an inline function it will execute that function and generate the component anew with every single render. In other words, your Home component is being unmounted and remounted with every render. Try this instead, which is the standard way of rendering a component via a route with props:
<Route exact path='/home' render={() => (<Home props={props}/>)} />
Related
I’m using the last release of React Router and I want to know what is the best solution to show different component that are nested in a parent component.
I’ll try to explain myself better.
I have a route R with path /r1.
This route loads component A.
Component A has inside others 3 components B, C and D that I should show in the same page with component A only when the user press a specific button in component A.
So I want to be able to add a description in route R to manage this. For example to show component B the router could be /r1/b.
Now I did this with a state variable inside component A but I think should be better if I can use some React Router property.
Thanks
You can create nested routes component, and it will manage nested routes.
export default function NestedRoutes() {
return (
<Switch>
<Redirect exact from={"/r1"} to={`/r1/A`} />
<Route path={`/r1/A`}>
<ComponentA />
</Route>
<Route path={`/r1/B`}>
<ComponentB />
</Route>
// Or to some not found component
<Redirect to="/r1/A" />
</Switch>
);
}
I'm using Switch with my route entries. The problem was that I didn't know how to render a component that I wanted to pass by props to another component.
I added a prop component to my parent component A and in my route I wrote something like this:
<Route path="/r1/hub/A" render={() => <A /> //this render only A
<Route path="/r1/hub/A/B" render={() => <A component={B} /> //this render A with B
In component A I used React.createElement to render component B with others properties that component A has to inject.
I have React application which has a structure similar to the following.
class App extends Component {
render() {
return (
<div className="App">
<NavBar />
<Router>
<Switch>
<Route path="/login" component={LoginPage} />
<Route path="/" exact component={DashboardPage} />
<Route path="/admin" exact component={AdminPage} />
// many other routes
<Route component={NotFound} />
</Switch>
</Router>
</div>
);
}
}
I do not want the login page to display the <NavBar /> element. I tried using the sessionStorage to get the userId and only display the navigation if the value is set. When I do this and go to the login page and the nav bar is not there. But when I log in, it's still not there. If I refresh however, it will appear.
I know one way to solve this is to make some sort of wrapper around the pages that do want the navigation, but I'd rather not have all of that code duplication, etc.
I feel this must be a common want, and I'm missing something dumb. Any help would be appreciated. I'm new to React so I don't follow everything that's going on here. Thanks.
I think your way of conditionally showing the NavBar is the right way. The question is how to trigger a state change so that the render method takes care of hiding and showing the NavBar, when you log in and out. I suggested maintaining a isLoggedIn state in your App component, and rendering the NavBar based on that, instead of directly accessing the SessionStorage. You could then use a custom event to update the state, when SessionStorage changes.
See this question for updating state based on Storage (in short, you fire and handle a custom event for storage changes): How to listen to localstorage in react.js
This might still be more code that you had hoped for, but it's more aligned with how React works, to derive the view (render) from component state.
I recently reconfigured my React app, and it seems that I have broken the functionality of my parameterized routes. Rather than going too deep into how it used to work, I'll describe what I am currently stuck with and what I am aiming to achieve...
In a navigation panel on the side of my page, a user can view a list of links to resources - the urls for these links would be something like:
user/123
user/456
user/789
group/123
group/456
group/789
Clicking the first link will now render the User component in the main div on my page (rendering in {this.props.children} - see App.jsx below), and a call to componentDidMount() pulls data for the user with id 123 and populates the component. Ok, so far, so good.
However, if a user now clicks on the link for user/456, nothing happens. The url in the navbar changes, but the User component does not re-render, though clicking a link for a group will correctly clear out the User component and render the Group component instead... then, of course, I have the same problem with the groups, etc...
How can I force the re-rendering of a component when the pathname remains the same but the parameter has changed? If I've clicked the link for user/123 and then I click the link for user/456, I want that User component to re-render and pull the new data.
Other relevant code...
index.js
import { Router, Route, browserHistory } from 'react-router';
<Router history={browserHistory}>
<Route path="/" component={App}>
<Route path="/user/:id" component={User} />
<Route path="/group/:id" component={Group} />
</Route>
</Router>
App.jsx
<div className="App">
<div className="body_section_container">
<div className="body_section main">
<Nav />
{this.props.children}
</div>
<div className="body_section sidebar">
<Search searchModel={this.searchAll} user_list={this.state.user_list} group_list={this.state.group_list} organizations_list={this.state.organizations_list} />
</div>
</div>
</div>
Try plugging into componentWillReceiveProps, which should fire when the route params change. Then you can receive the new route params, submit a new query, and update state.
In the Route component, specify a key.
<Route path={YOURPATH} render={(props) => <YourComp {...props} keyProp={id} key={id}/>} />
when react see a different key, it will trigger rerender.
I think I've got some issue with react router. How can I prevent react router from re-rendering a previously rendered page?
I have router code like this:
class App extends React.Component {
render() {
return (
<div>
<NavBar/>
{this.props.children}
</div>
);
}
}
ReactDOM.render(
(
<Router history={hashHistory}>
<Route path="/" component={App}>
<IndexRoute component={Gateway} />
<Route path="home" component={Gateway} />
<Route path="categories" component={Categories} />
</Route>
</Router>
), document.getElementById('my-app')
);
When I first visit the page, it hits index, Gateway component got rendered. Then I click on "categories" link, and Categories component got rendered. Then when I click "home" link again, the component Gateway got re-rendered. Its state got RESET. This is really frustrating, as I could not figure our why its state got reset.
Is there any solution for this?
If there is any state you want to be saved, you should store it somewhere, such as the component's state (or the redux state if you use redux).
In react, you can define the function shouldComponentUpdate() within components in order to force React not to re-render your DOM. But in the case of the react-router, the DOM of the first route is destroyed (not just hidden) and therefore should be re-rendered.
I have a React MaterialUI AppBarcomponent with property title , that I am changing based on the value returned by window.location.pathname. So as the page/url changes, the title will change with it. Looks something like below:
<AppBar
title={this.renderTitle()}
/>
renderTitle() {
if (window.location.pathname === '/home'
return 'home';
} else if (window.location.pathname === '/login'
return 'login';
}
The issue I am running into is that renderTitle() does not get executed if a different component (so not the AppBar) causes the page/url change.
E.g. another separate React component on the page triggers the page to change, which I'd hoped with trigger renderTitle(), but it doesn't... thus the title property never updates. So if I am navigating from /home to /login, the following will happen:
pathname is /home
user presses a button which runs a function, submit(), which is used to change the page w/ react-router
renderTitle() is run at this point, but window.location.pathname is still returning the previous page
submit() changes the page to /login
window.location.pathname is now correctly set to /login, but it is too late as renderTitle() has already been run
any help is appreciated, thanks
The best way is to use react-document-title library.
From documentation:
react-document-title provides a declarative way to specify document.title in a single-page app.
This component can be used on server side as well.
If your component that renders AppBar is an actual route you can just read the pathname from the props that react router injects.
<Router>
<Route path="/" component={App}>
<Route path="about" component={About} />
<Route path="inbox" component={Inbox}>
<Route path="messages/:id" component={Message} />
</Route>
</Route>
</Router>
For example in App, About, Inbox and Message you have access to the router props. And you can also pass the props to their children.
render() {
return (
<AppBar
title={this.renderTitle(this.props.location.pathname)}
/>
);
}
And in your function just use the parameter to return the correct result. Now because you are using props your component will update automatically when they change.