When I use custom hash history in my app, the confirm navigation mechanism does not work. I have modified the react-router confirm-navigation example to use custom hash history and successfully reproduced the problem.
I set the router leave hook (router.setRouteLeaveHook) and in the hook I return a string to indicate I do not want to leave the route.
When I push the BACK browser button, the browser URL will change to wherever the BACK button history navigates to, and reactRouter will correctly display a confirmation dialog box. On this dialog box I push the "cancel" button to indicate I don't want to leave the route, and my component remains visible and the route does not change. The problem is that the browser URL does not change back to where it was originally before I pressed the BACK button.
Is anyone else seeing this?
This is what I changed in examples/confirm-navigation/app.js to reproduce the problem.
import React from 'react'
import { render } from 'react-dom'
import { createHashHistory } from 'history'
import { browserHistory, Router, Route, Link, useRouterHistory, withRouter } from 'react-router'
let myCustomHashAppHistory = useRouterHistory(createHashHistory)({ queryKey: false })
and then in the app render I pass my myCustomHashAppHistory:
render((
<Router history={myCustomHashAppHistory}>
...
...
Related
Code Sandbox link:
and trying to follow this article
On successful login(/auth/login), the user should be routed to the dashboard(/admin/summary). If the login is successful, I am also storing an access token.
I have a PrivateRoute component for this. The problem is that on successful login, the URL is getting updated but the component is not getting rendered.
PS: about the dashboard, this is a single page application so, the dashboard has topbar, sidebar, and the right content and altogether these things are coupled inside <AdminLayout/>. So, in my AppRouter, I have to render the <AdminLayout/> and just any one component.
All the react and redux code is included in the code sandbox.
Since in your code you create your own history object (it happens in you history.js file, when you call createBrowserHistory()) but doesn't pass it to your Router, nothing happens.
There are 2 possible solutions:
1. Don't create a history object yourself, but use useHistory hook inside your component
Working Demo
With this approach, you should remove history.push from login.actions.js (which imports history) and use history.push in Login.js (which uses useHistory hook):
// login.actions.js
...
loginService.login(userid, password, rememberPassword).then(
(userid) => {
dispatch(success(userid, password, rememberPassword));
// history.push(from); <-- commented out!
},
(error) => { ... }
);
};
...
// Login.js
function handleSubmit(e) {
...
const { from } = {
from: { pathname: "/admin/summary" }
};
history.push(from) // <-- added!
dispatch(loginActions.login(inputs, from));
...
}
useHistory exposes the history object of BrowserRouter (I think this is implied in this official blog post).
2. Create a history object yourself, but pass it to a Router component
Working Demo
This approach would require you to make several changes:
Creating the history object on your own means you become responsible to provide it to a router component, but it can't be a BrowserRouter, but the base Router component (see these Github answers: 1, 2).
Once you import Router (instead of BrowserRouter), you need to get rid of any useLocation and useHistory imports, otherwise you'll get errors.
I also had to unify the history object export and imports, so that it is exported as the default export (i.e., export default history), and it is imported as the default import (i.e., import history from "./history"; instead of import { history } from "./history")
(P.S: this approach can be seen implemented elsewhere on SO, for example here or here (the latter explicitly installs history, but it's not needed in your case).
I am trying to understand the difference between BrowserRouter and Router of the react-router-dom (v5) package and what difference it makes for my example below.
The documentation says:
BrowserRouter
A that uses the HTML5 history API (pushState,
replaceState and the popstate event) to keep your UI in sync with the
URL.
Source: https://reacttraining.com/react-router/web/api/BrowserRouter
Router
The common low-level interface for all router components. Typically
apps will use one of the high-level routers instead: BrowserRouter, HashRouter, MemoryRouter, NativeRouter, StaticRouter
Source: https://reacttraining.com/react-router/web/api/Router
From what I understand is that I should be using BrowserRouter for my HTML5 browser apps and I have been doing this so far.
history.push(...) example:
I am trying to perform a history.push('/myNewRoute') within a thunk:
import history as './history';
...
export function someAsyncAction(input) {
return dispatch => {
fetch(`${API_URL}/someUrl`, {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json'
},
body: JSON.stringify({ input }),
}).then(() => {
history.push('/myNewRoute');
}).catch((err) => {
dispatch(setError(err));
})
};
};
history is defined as this module:
import { createBrowserHistory } from 'history';
export default createBrowserHistory();
and the history is also passed to my router:
import { BrowserRouter as Router } from 'react-router-dom';
import history as './history';
...
const App = () => (
<Router history={history}>
...
</Router>
);
Problem: history.push() will update the URL in the browser bar but not render the component behind the route.
If I import Router instead of BrowserRouter, it works:
// Does not work:
import { BrowserRouter as Router } from 'react-router-dom';
// Does work:
import { Router } from 'react-router-dom';
BrowserRouter ignores the history prop as it handles the history automatically for you. If you need access to the history outside of a react component, then using Router should be fine.
You can access history via the useHistory hook let history = useHistory(); to perform history.push() for BrowserRouter.
Looking at the HTML5 History API documentation, it seems that the history API preserves state for the user automatically. Say you are at page 1 initially and page 1 has a page outlook A. You performed some actions that changes the page 1 outlook to B. If you now moves to page 2, when you click the back button on the browser, you will be direct back to page 1. History API preseves your state so it knows to render outlook B to you, so that is the advantage of using BrowserRouter. Though I am not 100% sure, I suppose Browser doesn't come with this functionality and in which case it will render outlook A when you get directed back to page 1. This is not true. I am not sure about the difference.
I have the same issue.
BrowserRouter and useHistory() hook have been used for my component. And createBrowserHistory() has been used for redux-saga. But, the page has not moved by redux-saga such as your case.
Adding to that, my source has been developed using BrowserRouter, I don't want to replace it to Router component.
As my poor investigating, I found that both history objects are different. (I compared them with if and ==.) I guess it is the reason.
To solve it, I save the reference of the history object got by useHistory() to some global utility code, and use it in redux-saga code. Then, it works well.
I don't think this is the best way, but I couldn't find the best and official way yet.
I want to load multiple components on a single page and have different routes for all of them. For example i hit a route /article/1 and it loads a component, after scrolling through completely through that article i want the route to change to /article/2 and the corresponding article to load. I am using react and react router, basically i want 4 (article/3 , article/4) articles on a page and all these should be scrollable with the route changing as i scroll onto a particular article. How can i achieve this using react and react-router?
use react-perfect-scrollbar package from npm.
index.js (main entry point of your application) add this css
import 'react-perfect-scrollbar/dist/css/styles.css';
your component file where you want on scroll change url
import PerfectScrollbar from 'react-perfect-scrollbar';
import { Redirect } from 'react-router-dom';
handleScroll = () => {
<Redirect to="/article/2" />
}
<PerfectScrollbar onYReachEnd={this.handleScroll}> // when you reach then end of screen it's call handleScroll function and redirect to other url.so based on your requirements you can pick up from here.
// your articles code..
</PerfectScrollbar>
First things first is this possible to have 2 components on a page one displaying simple static markup but the second one in my parent is going to be a div that displays a link for each item in an array and if you click on it at the bottom of the div then data will be displayed for each one?
If this is possible are dynamic props as simple as performing .map inside the element and printing out a route?
Will also add that I am receiving the following on my Router object but I installed react-router globally though it is also in my node_modules folder.
'react-router' does not contain an export named 'hashHistory'.
import React, { Component } from 'react';
import { Router, Route, IndexRoute, hashHistory } from "react-router";
class DetailsComponent extends Component {
render() {
return (
<Router history={hashHistory}>
// in here will map this.props.data and for each one print a route
// the component for that route will be a DetailedViewComponent that
// that takes in the data in the props and renders it
// so i might need a link? in this render method aswell?
</Router>
);
}
}
export default DetailsComponent ;
React Router match params can be used to render content dynamically
ie. <Route path="/dynamicroute/:id" component={DynamicComponent}/> will provide an id param that can be retrieved via props.match.params inside <DynamicComponent/>
Spoke to some more senior react developers and they said what I was after was npm package Component-Router I haven't got back onto the project just yet but will post full code once completed :)
I am trying to use react-router v1.0.0 for full page and partial reloadable urls.
I have the following "History.jsx" file,
import BrowserHistory from 'history/lib/createBrowserHistory';
export default new BrowserHistory();
and I import it in my main entry file "app.jsx" like following,
import React from 'react';
import ReactDOM from 'react-dom';
import Router from 'react-router';
import Routes from './../utils/Routes.jsx';
import history from './../utils/History.jsx';
ReactDOM.render(
(<Router history={history}>{Routes}</Router>),
document.getElementById('pageSpecific')
);
Now when i navigate to "localhost:8080", it shows the page good. When i click on a href in the page, it takes to "localhost:8080/example" correctly without the "#" in the URL and it does not reload the page. Its all good.
Now that my URL is "localhost:8080/example" and when i try to refresh the page, it says "cannot get /example". This is problem which i am not able to solve!
Am i doing anything wrong? I am really struck in this place!!