react-router for navigating directory - reactjs

I am building a component in my app that allows the user to navigate a directory which contains sub-directories and files. There is no limit on the number of sub-directories.
I would like to use the URL to indicate position with the sub-directories. For example, take this structure:
- dir
-- sub-dir1
---- sub-dir2
------ sub-dir5
-------- image.jpg
---- sub-dir3
---- sub-dir4
If someone has navigated to sub-dir5 then I would like the URL to show:
`myapp.com/dir/sub-dir1/sub-dir2/sub-dir5`
While I know how to do this if the folder structure was known in advance using :param values, I'm not sure about how to tackle setting up the routes when there could be any number of sub-directories.
I'm using react-router v4

Only way to do this is to create a root route which will accept one (optional) param which is your file system path.
<Route exact path='/:path' component={ DirListing } />
Then you need to parse it (split by /) in your component to make sure it is valid. Once you got your path, you can load file list and show it to a user.
I would go even that far that you don't really need React Router for this, as you are going to end up parsing the routes yourself anyway. React Router makes is a bit easier though.
One last note, make sure you redirect all of the requests back to your react app (or you will end up with server side listing).

How about,
import React from "react";
import ReactDOM from "react-dom";
import {
BrowserRouter as Router,
Link,
Route,
Switch
} from "react-router-dom";
ReactDOM.render(
<Router>
<Switch>
<Route exact strict path="/:folderPath+/" component={DirList} />
<Route path="/:folderPath+/:fileName" component={Detail} />
</Switch>
</Router>,
node
);
or otherwise for the rendering part,
ReactDOM.render(
<Router>
<Switch>
<Route exact strict path="/:folderPath+/:fileName" component={Detail} />
<Route path="/:folderPath+/" component={DirList} />
</Switch>
</Router>,
node
);
This takes route name which ends with / to <DirList /> otherwise to <Detail />.
strict is needed to distinguish whether a path contains ending /.
exact is required since strict allows sub paths. Otherwise a path some/folder/file.png can fall into /:folderPath+/ when it comes to the upper case of the code example, and a path some/folder/ can fall into /:folderPath+/:fileName for the lower case of the example by recognizing
the path with params: { folderPath: 'some', fileName: 'folder/' }
as referred in Route path doc, Route path regExp rules
Route exact and strict doc

Related

How do I make a url contain multiple sections? React

So full disclosure, I'm not sure how to ask this question properly, but I do have a decent example. I'm making a React app and I'm trying to make the url more "descriptive" I suppose.
So it starts off at Home, then I go to a Products page and the url changes from /home to /products. This part is fine.
When I want to go to a specific product from the product page, I want the url to change to /products/example instead of just /example. Do I have to specify this with the Links or is there some cleaner way to get it done?
Right now my only answer is to make the link go to /product/example and have the App.js route to the same url. I'm not sure how to properly ask this question for a Google search so I had to ask it here. If you have an idea how to specifically phrase what I'm asking, I'd appreciate that too.
Thanks in advance.
I believe the example in your URL /products/example is the product name for your product. If so, this can be done in putting the product name as an URL parameter using react-router or react-router-dom if you still have not.
by declaring the route as
import { Switch, Route } from "react-router-dom";
const Router = () => (
<Switch>
<Route exact path="/home" component={()=>return <h1>Home</h1>} />
<Route exact path="/products" component={()=>return <h1>Products</h1>} />
<Route path="/products/:productName" component={props=>return <h1>props.match.params.productName</h1>} />
</Switch>
);
export default Router;
more on that here

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.

ReactJS Values In The URL Always Visible

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

React-router not matching query string

My routes are defined as follows:
<Router history={browserHistory}>
<Route path="/" component={App}>
<Route path="experiments">
<IndexRoute component={Experiments} />
</Route>
<Route path="*" component={NoMatch}/>
</Route>
</Router>
When I visit /experiments, things work as expected and the Experiments component is rendered. However, when I manually enter a URL with query parameters, example: /experiments?offset=50, the route doesn't match!
But when I navigate using <Link to={{ pathname='/experiments', query={offset:50} }} />, things work as expected. The Experiments component is rendered and this.props.location.query.offset is set to 50.
How do I get the Route to match when a URL with query string is entered manually (or copy-pasted)?
It seems route should match automatically url-with-query-‌​string-not-matching-‌​react-router-route, but it doesn't seem to be working for me.
Edit:
I narrowed down the problem to the catch-all route path="*". When I remove this route, everything works (e.g. when I visit /experiments?offset=50). But no routes are matched when the catch-all Route is present, even though it is at the bottom of the precedence list.
You need to make use of historyApiFallback with history={browserHistory} to load your route when you manually enter it.
what historyApiFallback does, is make it so your server returns index.html for whatever URL you try to access and since your routes are then configured with respect to index.html so you can access any of the route url directly
In you webpack add
devServer: {
historyApiFallback: true;
}
Ok, turns out this was an entirely unrelated issue. I was using redux-auth which was causing a redirect to the wrong URL pathname. This was happening after the react-router did its parsing and route matching. Once I fixed that, route matching worked perfectly. I was able to parse the query string from a URL like /experiments?offset=50 using the Route config in my question above.

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