Given this React router configuration:
<Router history={browserHistory}>
<Route path="/farm/:type?period=:period" component={Farm} />
<Route path="/pen/:penId" component={Pen} />
<Route path="/pen/:penId/cow/:cowId" component={Cow} />
<Route path="*" component={Farm} />
</Router>
Why is http://localhost:8080/farm/average?period=day only matching the catch-all route and not the first one?
Query string parameters don't need to be included in the <Route> definition.
Changing the route definition to <Route path="/farm/:type" component={Farm} />
solved the problem.
Query string parameters are still available under props.location.query
Related
I am using the same component for three different routes:
<Router>
<Home path="/" />
<Home path="/home" />
</Router>
Is there anyway to combine it, to be like:
<Router>
<Home path=["/home", "/"] />
</Router>
For Reach Router: (https://reach.tech/router/example/)
With the exact sample shown, the only way I can see how to do this(on a single line) is with a wildcard.
To find a way to reproduce this without side effects, we would need to see the entire nav menu.
<Router>
<Home path="/*" />
<Chicken path="chicken">
</Router>
...
const Home = props => {
let urlPath = props["*"]
// URL: "/home"
// urlPath === "home"
// URL/: "/"
// urlPath ===""
}
You could continue with other paths below Home and the router would allow them to process.
Check out the the example using a wildcard and reach router on codesandbox, I wrote!
Note: This is a catch-all, but without parsing a parameter is the only single line solution I saw.
Some DrawBacks include Home rendering instead of '404', etc.
//This could be resolved with an if statement in your render
//It will not produce the intended URL either for /home, and I have not looked into that since it is not part of the question.. but if it matched props[*] I'm sure you could redirect or something.
You can read more about the Route Component for Reach Router.
https://reach.tech/router/api/RouteComponent
I wasn't happy with the wildcard solution from the documentation and #cullen-bond because I had to map many other paths and came up with this solution:
<Router>
{["/home", "/", "/other", "/a-lot-more"].map(page => <Home path={page} />)}
</Router>
Example: https://codesandbox.io/s/reach-router-starter-v1-forked-6f44c?file=/src/index.js
Depending on the situation you're dealing with, <Redirect /> could also make the work.
<Router>
<Redirect from="/" path="/home" noThrow />
<Home path="/home" />
</Router>
You can use a single component for mutiple paths, by using a array of routes.
code example :
import sampleComponent from './sampleComponent'; // single component for mutiple routes
<Router>
<Switch>
{["/pathname_1", "/pathname_2", "/pathname_3", "/pathname_4", "/pathname_5", "/pathname_6"].map(pathname => (<Route exact path={pathname} component={sampleComponent} />) )}
<Switch>
<Router>
I used same component for different routes. When route changes, I want the component to be rendered.
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/hotels" component={HotelsPage} />
<Route path="/apartments" component={HotelsPage} />
</Switch>
When I change the route path from /hotels to /apartments, the component HotelsPage doesn't refresh.
What is the cool approach for this?
One of the ways you can get this sorted is by passing the props explicitly like :
<Route path="/hotels" component={props => <HotelsPage {...props} />} />
Firstly you can aggregate the Route into one like
<Switch>
<Route exact path="/" component={HomePage} />
<Route path="/(hotels|apartments)" component={HotelsPage} />
</Switch>
and secondly, your HotelsPage component is rendered both on /hotels, /apartments, it is similar case like path params, whereby the component doesn't mount again on path change, but updates thereby calling componentWillReceiveProps lifecycle function,
What you can do is implement componentWillReceiveProps like
componentWillReceiveProps(nextProps) {
if (nextProps.location.pathname !== this.props.location.pathname) {
console.log("here");
//take action here
}
}
DEMO
I guess just passing useLocation().pathname will resolve issue
useEffect(
() => {
// Your logics
});
}, [useLocation().pathname])
Ok, I'm fed up trying.
The onEnter method doesn't work. Any idea why is that?
// Authentication "before" filter
function requireAuth(nextState, replace){
console.log("called"); // => Is not triggered at all
if (!isLoggedIn()) {
replace({
pathname: '/front'
})
}
}
// Render the app
render(
<Provider store={store}>
<Router history={history}>
<App>
<Switch>
<Route path="/front" component={Front} />
<Route path="/home" component={Home} onEnter={requireAuth} />
<Route exact path="/" component={Home} onEnter={requireAuth} />
<Route path="*" component={NoMatch} />
</Switch>
</App>
</Router>
</Provider>,
document.getElementById("lf-app")
Edit:
The method is executed when I call onEnter={requireAuth()}, but obviously that is not the purpose, and I also won't get the desired parameters.
onEnter no longer exists on react-router-4. You should use <Route render={ ... } /> to get your desired functionality. I believe Redirect example has your specific scenario. I modified it below to match yours.
<Route exact path="/home" render={() => (
isLoggedIn() ? (
<Redirect to="/front"/>
) : (
<Home />
)
)}/>
From react-router-v4 onEnter, onUpdate, and onLeave is removed,
according the documentation on migrating from v2/v3 to v4:
on* properties
React Router v3 provides onEnter, onUpdate, and onLeave
methods. These were essentially recreating React's lifecycle methods.
With v4, you should use the lifecycle methods of the component
rendered by a <Route>. Instead of onEnter, you would use
componentDidMount or componentWillMount. Where you would use onUpdate,
you can use componentDidUpdate or componentWillUpdate (or possibly
componentWillReceiveProps). onLeave can be replaced with
componentWillUnmount.
For react-router-6 the Redirect component has been replaced with Navigate.
Below userState will be either null or populated depending upon if user is logged in or not, can be your Redux state for example.
<Route path="/protectedRoute"
element={userState ? <protectedComponent/> : <Navigate to="/login"/>}/>
So currently, I want to have a route where it could be any enumeration of ids (kind of like a file browser). It looks like this:
<Route path="/browser">
<IndexRoute component={FileBrowser} />
<Route path=":id">
<IndexRoute component={HardDriveBrowser} />
<Route path="folders/**/:folderId" component={FolderContents} />
</Route>
</Route>
However, if I visit a route such as /browser/1/folders/2, it does not match. I think it is expecting the splat.
Is there a way to specify the splat as optional, or have it default to an empty string?
In react-router v4, simply put ? at the end to make the parameter optional. In react-router v2, you use parenthesis to make a parameter optional. ex: (:folderId) would make that optional.
My React application is hosted at www.mywebsite.com/myreact
When I defined my routes, I've done something like this:
<Router history={history}>
<Route path="/" component={App} />
<Route path="login" component={Login} />
</Route>
</Router>
Although, it keeps complaining that /myreact is not defined in the route.
When I define it, that way:
<Route path="/myreact" component={App} />
and I try to access the URL www.mywebsite.com/myreact/login, the browser throw a 404 error.
But I can access www.mywebsite.com/myreact properly though.
What should I do?
Thanks.
You should be able to create a custom history object with a different basename for your apps 'root' url. with the useRouterHistory enhancement when creating the history object
https://github.com/reactjs/react-router/blob/master/docs/API.md#userouterhistorycreatehistory
some relavent comments in this github issue thread
import { createHistory } from 'history';
import { useRouterHistory } from 'react-router';
const browserHistory = useRouterHistory(createHistory)({
basename: '/myreact'
});
your routes files should now work using browserHistory
<Router history={browserHistory}>
<Route path="/" component={App} />
<Route path="login" component={Login} />
</Route>
</Router>