How to access value of a routing parameter in react? - reactjs

I want to have a 'dynamic route' for a section of my app, which was done like this:
<Route path="path(/:id)" component={Component} />
So far this works, but in Component I would like to access the value of id because it changes a bunch of things depending on which it is. How can I do that?

In your component, you would access this via props.
this.props.params.id
Here is the guide from react-router that goes into more detail as well.
https://github.com/reactjs/react-router-tutorial/tree/master/lessons/06-params

Related

Update react Context from children or alter component structure?

This question focuses on the Header component: So in my app. I have a something that looks a bit like this with a few more components and plenty more routes:
return (
<SiteLayoutContext.Provider value={siteConfiguration} >
<div className="topContainer">
<BrowserRouter>
<div className="header">
<Header/>
</div>
<div className="mainWrapperContainer">
<div className="contentWrapper">
<Route exact path='/login' component={Login}/>
<Route exact path='/home' component={Home}/>
<Route exact path='/about' component={About}/>
<Route exact path='/collection/:collectionName' component={CollectionLandingPage}/>
<Route exact path='collection/:collectionAlias/id/:itemId' component={ItemView}/>
</div>
<Footer/>
</div>
</BrowserRouter>
</div>
</SiteLayoutContext.Provider>
)
What I'd like to accomplish:
I can currently set a logo for the header. This is great, but I'd like the user to be able to select a custom logo, one that will replace the global default, if they are within a collection.
To define 'within' a collection, the route will start with /collection/ so in the example below, both the ItemView and the CollectionLandingPage should have this custom logo.
I need to be able to tell my header that it's currently within a collection, and I want to limit renders and redraws to improve performance. I have an api endpoint that I fetch to grab collection info, which would tell me if a custom logo has been set, and what the href should be.
What I've tried: My original thought was to rip the header out of the main return() shown above, and instead place it within every component, that way I can use React's useLocation() hook to check the the url, and only fetch the collection's logo if1) we're within a collection and 2) a custom logo has been set.
My issue with this method is that I now have to enter the Header within every single component, instead of how it is currently implemented.
My second thought is to wrap it all within some kind of context, consume it in every component, and update it based on the url, which would then fetch the relevant info, but this just feels off. I suppose I could fetch the information for the collection and update a new CollectionInfoContext every time I hit /collection/:collectionName which would only update when the collectionName changes?
I'm kind of just looking for suggestions on how to implement this because well... I feel like there's an option I haven't listed that's probably much easier and more reasonable... as is the stackoverflow standard.
Disclaimer: I'm a react context api novice
If you're not using Redux or another state management solution, a context is definitely a reasonable way to share data across your application, UI themes are actually one of the recommended use cases in the React docs.
The only issue I could see is that changing the state for only certain components would require a way of resetting the context for other places where you just want a standard logo. But reading the URL name could solve that by simply storing the path name and using it inside of Header to render the custom logo if the path includes collections. If Header can read the path name all on its own, you may not even need a context if that's the only condition that's dynamic everywhere.

How to use Redux Form Wizard with permanent URLS per page

I'm working to build a signup > profile setup flow for a new application which is using React + Redux.
I found the following example for a redux form wizard:
http://redux-form.com/6.7.0/examples/wizard/
This seems to be the closest example but the problem is each step in the wizard does not change the URL, so if the user clicks the browser's forward/back btn or refreshes their browser, it will break.
Would it be OK to make Redux form wizard have permanent URLs? How can I approach this as a beginner?
Something where the wizard has URLs like:
/wizard/name
/wizard/profile
/wizard/photo
Would it be OK to make Redux form wizard have permanent URLs?
The way how it's implemented depends on every use case. I don't see any problem why it wouldn't be ok.
The wizard example tells you everything you need to know regarding your approach.
Talking about the official example, you could approach this in the following way:
Create a /wizard/name route which would render the same WizardForm.js component;
If the subpath is /name, render the WizardFormFirstPage
Same for the other subpaths.
I recently implemented a redux-form wizard with client-side routing. I will share some of the details here for posterity...
I have a component called MainContent which has several React-Router 4 routes. One of these routes looks like this:
<Route path={'/profile/:profileSection'} component={Profile} />.
This route loads a "wizard" style redux-form that the user fills out to set up her profile.
Note the profileSection route parameter. If the current URL is:
https://www.myawesomeapp.com/profile/my-age, the Profile component will receive a profileSection prop from the router with a (string) value of 'my-age'. This would be used to load the form "step" that asks the user her age.
Profile is a stateful component. Its render method returns the wrapped components for each step. It looks roughly this like this:
return (
<div>
<Step1 {...this.state} {...this.props} />
<Step2 {...this.state} {...this.props} />
<Step3 {...this.state} {...this.props} />
</div>
)
}
The profileSection router prop gets passed into each of the "step" components. These step components are created from an HOC. The HOC decorates each component with the following behavior:
Match a regular expression against the profileSection prop.
If it matches, the component's render method returns the markup for said step.
if it does not match, the component's render method returns null.

React-router child-route navigation not working

I'm trying to follow the react-router tutorial here trying to navigate using a child route and it doesn't work.
For example given this route definition:
export default <Route path="wifi" component={ Wifi }>
<IndexRoute component={WifiView}/>
<Route path="list" component= {WifiListView}/>
<Route path="connect" component={WifiConnectView}/>
</Route>;
If we are on "/" and navigate to "/wifi" we are good. The WifiView is presented however if if from "/wifi" we call hasHistory.push('list') it doesn't find the route. I would assume that the route is relative to its current location since I'm not using the "/" but that isn't being respected.
Also the document said:
You can also use the router that Router provides on "context". First,
you ask for context in the component, and then you can use it...
But I don't see anything that mentions how to do that in TypeScript so I'm using the static hashHistory.
It looks like novice questions but I had nowhere to ask since the suggested Discord channels are all dead... Can anyone help with those?
Thanks! Appreciate any help!
Ok finally found the replies to my questions...
As for today, react-router don't support relative navigation which means, it hast to navigate to the whole chain of routes and that is why hasHistory.push('list') doesn't work.
In order to get the context.router we need to use withRouter high order component but that isn't exposed on the TypeScript definition files they provide.

React/Redux Where to save State

I am having trouble understanding some ReactJS and Redux principles,
In Redux we have a store and a set of reduceres that give your final state ( this part I get).
A Component receives props from their parent component, in case of Redux it passes the full state down with the Provider Component.
Now, lets assume this use case, I have my app state something like this :
auth : { name,id, ..etc} -> this is actually a JWT Token with a set of claims...
I am building a Container (Page) to be able to edit user profiles, the catch here , and where I am having trouble, I also want this page to handle a arbitrary user edit (in case admin is editing a account).
I am rendering my Page by using redux-router like this :
<Route path="/user" component={RequiresAuth(UsersPage) } >
<IndexRoute component={RequiresAuth(UsersOverview) }/>
<Route path="/user/overview" component={UsersOverview} />
<Route path="/user/account" component={AccountManagement} >
<IndexRoute component={RequiresAuth(AccountManagement) }/>
<Route path="/user/account/:userid" component={AccountManagement} />
</Route>
So reading the docs, I assume my props will have a userid which will override my default user if present.
Questions:
Is this approach correct? The Route Handling?
If I pass a userid param on the route, how do I proceed to load the user info and where? The way I see it, I need to dispatch an action, but I am not sure where to set the state , if on the store, or the component.
Also, Where would I load my user information? (constructor comes to mind)... or should it be in WillMount/WillReceiveProps?
Thank you.
If you really have a hard time to understand React/Redux principles i suggest you to try this tutorial :
https://github.com/happypoulp/redux-tutorial
It helped me a lot when i first started with React/Redux. By the way it's a bit hard to really answer your question because you re asking specific questions on a really specific case :)

React-router: How can props be passed down to child components?

I'm not sure if I'm approaching this in the right way at all, so a bit of background first:
Let's say I have countries and cities in each country that I'm going to fetch from two stores, CountryStore and CityStore in the topmost route (view1). I'm trying to set up react-router so that I have nested routes like this:
<Route name="app" path="/" handler={App}>
<DefaultRoute name="view2" handler={View2}/>
<Route name="view1" path='country/:countryId' handler={View1}>
<DefaultRoute name="view3" handler={View3}/>
<Route name="view4" path='city/:cityId' handler={View4}/>
< More nested routes />
</Route>
</Route>
So from what I've been reading up on, I've understood that I should have state in my top view1 and pass everything down as props to view3, view4 and any others.
So here's a fiddle where I've got things working by passing down props with the route handler in view1, and from links I'm passing params based on which each view can filter out what they need. But I'm wondering if there's a smarter way of doing this by passing down the props I'm going to need with each link somehow. Meaning that if in my city list I'm already iterating through all the city objects, can I with the city link pass down the current city as props somehow, so the city view wouldn't need to filter out its city each time?
I hope the question is clear enough, I'm thankful for any advice!
Your question is a little confusing (maybe because of the very generic variable/view names), but I think I see what you're getting it.
I think there are two parts of the answer: can you do this, and should you do this.
I believe it's definitely possible that you can do what you're suggesting. If you look at the params in View1, you can see that when the url is country/1 the params are { countryId: "1" }, but when the url is country/1/city/2, the params are { countryId: "1", cityId: "2" }. So, based on this, View1 could see the cityId param and decide to pass an additional property to its child, for example:
// In View1
var props = {
country: testCountry
}
if (this.props.params.cityId) {
props.city = (get the city object here);
}
return (
<div>View 1 wrapper: countryId {countryId}
<RouteHandler {...this.props} {...props}/>
</div>
);
However, I'm not really sure that you should. This is breaking the encapsulation provided by React Router; you're coupling two views by giving View1 direct knowledge about how one of its children, View4, works.
If you're really concerned about the performance hit of iterating over the cities more than once, it may be worthwhile to provide an ID-indexable data structure that View4 can use to look up the city directly (e.g. var city = this.props.whatever[this.props.params.cityId]).
Taking a step back, I personally thing the "get all the state and pass it down as props" that Bill describes in the answer you linked to might break down a bit in applications that rely on routing. I consider each view passed to the router via <Route handler={...} /> to be a view-controller—a miniature standalone app, as it were. Doing so, as Bill mentions, gives a better encapsulation of the domain that the route/route handler is dealing with, and I don't think that it makes debugging more difficult, as the routes declare exactly which view is acting as the top-level view-controller for any given URL (so if some data looks wrong you just go immediately to the view-controller for the current route).
If you use a nice composition strategy to connect your route handlers to flux stores (see the code at this Fluxxor issue as an example), it makes it even clearer how the data gets from the stores into the components.

Resources