ReactJS Values In The URL Always Visible - reactjs

I have a filter system for my products in ReactJS which basically has the following:
http://localhost:3000/category/women/subcategory/tops/sorting/null/price/null/size/null/color/null/brands/null/merchants/null
The Route is as follows:
<Router>
<Route path="/category/:cat/subcategory/:subCat/sorting/:sorting/price/:price/size/:size/color/:color/brands/:brands/merchants/:merchants" component={Products} />
</Router>
The Problem is that I want to show filters in the URL in when they have a value other than null. Current my component works but I have to display every single filter in the URL with a null value by default, this is causing my URL to be extremely long. The only way I thought possible was to do a permutation combination of all the possible URLs in the filter and direct them all to { Products } which is extremely silly. There must be something in the Router component that I'm missing?

You need to use optional params in this case.
As and example if you want to accept both sorting/ascending/price and sorting/price you can write your path as follows assuming you use react router v4.
<Router>
<Route path="sorting/:sort?/price" component={Products} />
</Router>
You can read more about this here: React Router with optional path parameter

Related

How to write right regular expression for my Route path in React JS

I have some troubles with writing regular expressions in my React JS application.
Suppose that my have to check only paths like "/articles/page-2" or "/articles/page-1" or just "/articles/". What is the right way for doing it correctly?
<Route path={'/articles/(page-)?:pageNumber?'}/>
I've tried following path, but it's not the right path. This route would render it even when URL is "/articles/-3"
For capturing only pageNumber is better to break into 2 routes. Create the first for capturing /articles only and the second with the desired pattern.
you can write as page-:pageNumber(\d), where \d means digit. you must also include exact={true}, to ensure an exact match for your path. With that you can use useParams later to extract pageNumber:
<Route path={'/articles'} exact={true} />
<Route path={'/articles/page-:pageNumber(\d)'} exact={true} />
Not sure if I understood, and also not sure if you can do that.. but try
<Route path={`/articles/${pageNumber ? "page-" + pageNumber : ''}`}/>

Can react router have a route with multiple option parameters where (e.g.) both are required, or none

Using react-router-dom I have a route like so:
<Route path='/:year?/:month?' component={ThingUsingYearAndMonth} />
But really I want BOTH year and month to exist (e.g. /2018/Dec or /2017/Jan) or neither. I.e. just /2018 wouldn't match
I would probably handle that using two routes -- one for when both are provided and one for when neither are provided:
<Route path='/:year/:month' component={ThingUsingYearAndMonth} />
<Route path='/' exact component={ThingUsingYearAndMonth} />
Try providing explicit parameters with regex:
<Route path='/:year(\\d{4})?/:month([A-Za-z]+)?' component={ThingUsingYearAndMonth} />
I don't think there is any mechanism provided by the react-router-dom to validate the route params. You are better off creating your own Higher Order Component and validate the route params in it. Or you can use regex to validate your params in the route itself.

How do I avoid rendering a component when another component in a similar path has already rendered when using URL params in React Router v4?

I'm trying to create RESTful routes for my application, but I'm having problems when it comes to routes with URL params.
Here are the routes that I want to have:
/accounts
/accounts/new
/accounts/edit
/accounts/:id
These is what my router looks like:
<Router>
<Route exact path="/accounts" component={AccountsList} />
<Route exact path="/accounts/new" component={AccountCreate} />
<Route exact path="/accounts/edit" component={AccountUpdate} />
<Route exact path="/accounts/:id" component={AccountDetail} />
</Router>
/accounts works fine, but when I go to /accounts/new or /accounts/edit, it also renders AccountDetail which is supposed to be located at /accounts/:id.
For the record, that I get that this is the correct behavior since /accounts/:id technically matches /accounts/new and /accounts/edit.
My question is if there's a way to make :id match with a specific pattern only (numbers only).
Try the < Switch> component of reactRouter.
Renders the first child < Route> or < Redirect> that matches the
location.
I think it's exactly what you are looking for.

Using multiple params with React Router?

<Route path="/:user" component={Home}>
<Route path="/:thing(/:version)" component={Thing}/>
</Route>
So, I've got two dynamic objects in my application that I'd like to be controlled by route params in react-router. Using the code above, both /0 and /0/3 take me to Home. I need /0/3 to take me to Thing. I'm not sure what I'm doing wrong here... Does react-router even support multiple dynamic params next to each other like this? I couldn't find anything in the docs.
What happens here is that you've given React Router two paths that can both match on /anything. By default then React Router matches the first one it can find.
To dig deeper, if I go to /pudding, React Router can't know if you meant /:user or /:thing. Since /:user occurs first, that option will be chosen.
You also need to make sure if nesting routes is what you want. Currently, your Thing route is nested below Home, which means that it is rendered via this.props.children in your Home component. So, for your current Thing route, Home will always be rendered too, with Thing as a child. If your Home component doesn't render this.props.children, Thing will not be shown.
I suspect you just want two different pages. What you could do to achieve that is the following:
<Router history={history}>
<Route path="/user/:user" component={Home} />
<Route path="/:thing(/:version)" component={Thing}/>
</Router>
This will make every /user/name go to the Home component, and every other /random (with an optional extra level) will go to Thing. If you wonder why in this case React Router doesn't take /user/name to the Thing route, it's because it still matches in the order your routes are specified. Because your Home route matches the requested URL, no siblings of this route are tested anymore.

Unit testing route matching with React Router 2

I’m trying to add unit tests for a React application and would like to test the routes provided by React Router (2.0.1). I’d like to test whether specific paths that I supply will match a route. I am writing my tests using Mocha and expect.
I’ve looked through the documentation on the React Router repository, but the only testing guide I could see was explaining how to test a <Link /> and how it’s rendered.
Say I have the following code:
// import statements omitted for brevity
export const routes = (
<Route path="/" component={App}>
<IndexRoute component={Index} />
<Route path="/foo">
<IndexRoute component={FooIndex} />
<Route path="add" component={FooAdd} />
<Route path=":fooId" component={FooDetails} />
</Route>
</Route>
)
ReactDOM.render(
<Router history={browserHistory}>{routes}</Router>,
document.getElementById('app')
)
How can I test that the routes created in the routes variable would match the following:
/
/foo
/foo/add
/foo/25
But not routes like:
/foo/bar/12
/bar
Essentially I want to check that every expected URL format has a route that will match it and that unexpected URLs don't match any routes.
I’m not interested in the elements that are rendered by the routes, so don't want to base my tests on checking whether a specific thing is rendered, only that a matching route was found and preferably some way of checking that it was in fact the expected route (I'd guess checking what the name of the component is or something?)
Any help is gratefully appreciated.
Thanks
We test exactly this in our test for matchRoutes: https://github.com/ReactTraining/react-router/blob/v3/modules/__tests__/matchRoutes-test.js
You can follow this pattern. If you can't identify your routes by reference, you can indeed assert on the components that were rendered as well.
As matchRoutes isn't exported, you'll want to use the match helper (otherwise used for for server-side rendering) instead, and check renderProps.routes or renderProps.components.

Resources