react router not updating browser's location bar - react-router

I met a weird problem here, I am using a simple router set up like:
<Provider store={store}>
<div>
<Router
location='history'
history={createHistory({queryKey: false})}
onUpdate={() => window.scrollTo(0, 0)}>
<Route path="/" component={Main}>
<Route path="datacenter/:name" component={App} />
<Route path="operation" component={OperationComponent} />
</Route>
</Router>
<DevTools />
</div>
</Provider>
and I have a nav list that manipulates the History:
<SelectableList subheader='OPERATIONS' valueLink={{value: this.props.location.pathname, requestChange: this.operationChanged}}>
<ListItem primaryText='Checks' value='/operation' onTouchTap={this.handleClose}/>
</SelectableList>
with action callback:
operationChanged = (evt, val) => {
this.props.history.push(val);
};
the problem is the navigation is working, when I click one of the list item, I am navigated to the path as expected, however, the selected path is not being updated to browser's address bar ...
Any ideas?
Thanks in advance
UPDATE *********
Turns out, it is an issue related to webpack-dev-server, while using this dev tool, the react-router failed to update browser's location bar ... did not figure out why though

Could be because on the Router you are setting:
location='history'
Try removing that line, also a JSBin or plnkr would be helpful so I could play around with it!
check out the docs here and follow the basic setup: Check out the bottom of the second example!

Related

React (5): Make route navigate to an external link

I'm trying to make react navigate to an external link from a route. I don't feel like adding an restyling the header.
<Switch>
<Route exact path='/'>
<PageLayout>
<LandingPage />
</PageLayout>
</Route>
<Route exact path='/example'>
<a href="www.example.com" />
</Route>
</Switch>
I'm just looking for the simplest way to do this. I don't want to have to restyle the header.
Preferably it would open up a new page.
Edit I've also tried
<Route exact path='/example'>
<Redirect to='https://www.example.com' />
</Route>
react-router-dom only deals with internal routing & navigation within a React app. If you want are trying to navigate/redirect to a URL that is external to your app from a matched route then I suggest using window.open and open in a new browser context, like a new window or tab. You can create a custom component to do this as a mounting effect.
Example:
import { useHistory } from 'react-router-dom';
const RedirectExternal = ({ to }) => {
const history = useHistory();
React.useEffect(() => {
window.open(to, "_blank", "noreferrer");
// use timeout to move back navigation to end of event queue
setTimeout(history.goBack);
}, [history, to]);
return null;
};
Usage:
<Link to="/example">www.example.com</Link>
...
<Switch>
<RedirectExternal from="/example" to="https://www.example.com" />
<Route path="/">
<PageLayout>
<LandingPage />
</PageLayout>
</Route>
</Switch>
It might just be easier to link to the external page directly though.
<a href="https://www.example.com" rel="noreferrer" target="_blank">
www.example.com
</a>
Since you are using react-router-dom, you could do the following to achieve an external link in navigation.
<Route
path="/myPath"
component={() => {
if (window) {
window.open(
"https://www.google.com"
);
}
return null;
}}
/>

Issue with connected-react-router

I have created the following routes using connected-react-router as shown below
<Switch>
<Route exact={true} path="/a" component={A}/>
<Route exact={true} path="/b" component={B}/>
<Route path="/c/:id" component={C}/>
</Switch>
But when I hit the url my.domain.com/c, the component does not get render. But when I go and give the url my.domain.com/c/12, then it works. I have tried setting exact={false} as well. Still it does not work. Any help will help me proceed further.
When you declare the route:
<Route path="/c/:id" component={C}/>
You are saying that the "id" it's mandatory. If you need render the page even if the user don't pass the id, you need to add "?":
<Route path="/c/:id?" component={C}/>

How to have react route path one/two/three?

I would like to have something like this
<Route
path="/one/two/three"
render={() => (
<Component/>
)}
exact
/>
But it does not seem to work locally when I wrap it all into a Router. I only see the contents of the Component when it is just /one, but I would like to have /one/two/three as the path (being my root - user lands on that path).
In react-router-v4 you can have below routes only,
<Route path="/one" render={() => (<Component/>)} exact /> //Direct route without any params
or
<Route path="/one/:two" render={() => (<Component/>)} exact /> //Route with params, here `:two` is the parameter to route
If you want to use routes like in your example, then this can be achieve using BrowseRouter basename attribute,
<BrowserRouter basename="/one/two">
<Route path="/three" render={() => (<Component/>)} exact />
</BrowserRouter>
And you Link should be like,
<Link to="/three"/> // renders <a href="/one/two/three">
Few reasons why this did not work for me.
I was missing output: { publicPath: '/' }, in my webpack config.
And weirder thing was that I was using PureComponent instead of Component which totally broke the rending when redirecting to the next step with similar path(x/y/z) or using Link.

ReactJs Blank page when I click on a link, but after I refresh the page contents show up

I am new to react and in my app it works fine apart from the fact that when I click on a link in the app to go to another page I get a blank page instead but after I reload/refresh the page contents appear.
I have used CDN files in my react app.
What might be the issue here?
This is how I am loading my urls which look like this
http://127.0.0.1/my-app/?page=history
and the links look like this
<i className="fa fa-home"></i>Home
My code for rendering URL's in my index.html file looks like this
var urlParams = new URLSearchParams(window.location.search);
var page=(urlParams.get('page'));
if(page=="home")
{
ReactDOM.render(<App content={<HomePage/>}/>,document.getElementById('root'));
}
else if(page=="history")
{
ReactDOM.render(<App content={<HistoryPage/>}/>,document.getElementById('root'));
}
else
{
ReactDOM.render(<App content={<Login/>}/>,document.getElementById('root'));
}
That's not the correct way of routing in react according to the documentation.
A simple solution while using cdn is to include react-router-dom from https://unpkg.com/react-router-dom/umd/react-router-dom.min.js
Then enter the code below as a replacement for what you are currently doing:
const { Switch, Route, BrowserRouter } = window.ReactRouterDOM;
ReactDOM.render(<BrowserRouter>
<Switch>
<Route path='/' component={HomePage} exact/>
<Route path='/history' component={HistoryPage} exact/>
<Route path='/login' component={LoginPage} exact/>
<Route component={Error404}/>
</Switch>
</BrowserRouter>,document.getElementById('root'));
You can also check out the documentation at this link

React Router props `location` / `match` not updating with `ConnectedRouter`

I've got my app setup as in the docs:
Step 1
...
import { createBrowserHistory } from 'history'
import { applyMiddleware, compose, createStore } from 'redux'
import { connectRouter, routerMiddleware } from 'connected-react-router'
...
const history = createBrowserHistory()
const store = createStore(
connectRouter(history)(rootReducer), // new root reducer with router state
initialState,
compose(
applyMiddleware(
routerMiddleware(history), // for dispatching history actions
// ... other middlewares ...
),
),
)
Step 2
...
import { Provider } from 'react-redux'
import { Route, Switch } from 'react-router' // react-router v4
import { ConnectedRouter } from 'connected-react-router'
...
ReactDOM.render(
<Provider store={store}>
<ConnectedRouter history={history}> { /* place ConnectedRouter under Provider */ }
<div> { /* your usual react-router v4 routing */ }
<Switch>
<Route exact path="/" render={() => (<div>Match</div>)} />
<Route render={() => (<div>Miss</div>)} />
</Switch>
</div>
</ConnectedRouter>
</Provider>,
document.getElementById('react-root')
)
I click on a Link or even dispatch(push('/new-url/withparam'))
However the props for match location are remaining the previous values or whatever the first page was.
What is happening?
This one has bitten me many times.
Your Switch and Route etc. MUST NOT BE INSIDE A CONNECTED COMPONENT!
If the component is connected, the props for match, location, etc. don't seem to get updated and propagate down to your routes.
This means don't connect your top level App or Root, or any other nested containers between the ConnectedRouter and Route
--
Update:
You may just need to wrap your component with
<Route render={ (routerProps) => <YourConnectedComponent { ...routerProps } />
I decided to add example to here as I feel it is valuable input - even tho, it's already answered.
I had similar problem, when I pushed url into router history, it changed URL but it didn't navigate properly on the component I wanted. I googled and searched for answer for hours, until I found this thread which finally helped me to find out what I made wrong. So all credits to #ilovett.
So here is an example, if someone will need it for better understanding:
I had code similar to this:
export const routes =
<Layout>
<Switch>
<Route exact path='/' component={ Component1 } />
<Route path='/parameter1/:parameterValue' component={ Component2 } />
</Switch>
</Layout>;
<Provider store={ store }>
<ConnectedRouter history={ history } children={ routes } />
</Provider>
It was working fine when I came to a project, but then I decided to refactor Layout component and I connected it to the store which caused that Component2 stopped receiving correct values in the ownProps.match.params.parameter1 and because of that it rendered component completely wrong.
So only thing what you need to do is move Layout outside of ConnectedRouter. Nothing between ConnectedRouter and Route can be connected to the store.
Working example is this then:
export const routes =
<Switch>
<Route exact path='/' component={ Component1 } />
<Route path='/parameter1/:parameterValue' component={ Component2 } />
</Switch>;
<Provider store={ store }>
<Layout>
<ConnectedRouter history={ history } children={ routes } />
</Layout>
</Provider>