I can see in this file (https://github.com/ReactTraining/react-router/blob/v0.13.3/modules/createRouter.js) that there is a refresh function but I have no idea how to call it. I'm fairly new to react-router, I've only used it to move between some pages a couple times using hashHistory.
Right now I am trying to use it so that when an install fails, the user is given the option to 'retry' which I plan to execute by refreshing the page where the install happens (the page the user would be currently on). Any help would be appreciated.
This is a node app that runs on electron, not a web app.
firstly, add react-router as a dependency
yarn add react-router or npm install react-router
Then (for react-router v5)
import { useHistory } from 'react-router'
const history = useHistory()
// then add this to the function that is called for re-rendering
history.go(0)
This causes your page to re-render automatically
For react-router v6 use the useNavigate hook instead:
import { useNavigate } from 'react-router'
const navigate = useNavigate()
// refresh
navigate(0)
If you're using react-router v6
import { useNavigate } from "react-router-dom";
const navigate = useNavigate();
const refreshPage = () => {
navigate(0);
}
You can use this to refresh Current route:
import createHistory from 'history/createBrowserHistory'
const history = createHistory();
history.go(0)
You don't really need react-router for this. You can just use location.reload:
location.reload();
Also that version of react-router you linked to is very old, I think it's linking to v1 when it's currently on v4.
I guess that you're using react-router.
I'll copy my answer from another post.
So you have few possibilities to do that, currently my favorite way to do that is using anonymous function in component prop:
<Switch>
<Route exact path="/" component={()=><HomeContainer/>} />
<Route exact path="/file/:itemPath/:refHash" component={()=><File/>} />
<Route exact path="/:folderName" component ={()=><Folder/>}/>
</Switch>
Or if you want to refresh with current url params, you'll need extra route (reload), and play a little with router stack:
reload = ()=>{
const current = props.location.pathname;
this.props.history.replace(`/reload`);
setTimeout(() => {
this.props.history.replace(current);
});
}
<Switch>
<Route path="/reload" component={null} key="reload" />
<Route exact path="/" component={HomeContainer} />
<Route exact path="/file/:itemPath/:refHash" component={File} />
<Route exact path="/:folderName" component ={Folder}/>
</Switch>
<div onClick={this.reload}>Reload</div>
React
window.location.reload();
working
if you want to re-fetch the data just do the below:
import { useLocation } from 'react-router'
const location = useLocation()
useEffect(() => {
fetchData()
}, [location.key])
I know that this is old, but I found a simple solution according to the documentation of react-router.
Just put that attribute on your Router, and whenever you are on a new Path it will force the page to reload itself.
<Router forceRefresh={true}>
Source:
https://reactrouter.com/web/api/BrowserRouter/forcerefresh-bool
This solution won't cause the undesired full page reload but requires you to make this modification to each page that needs refreshing:
export const Page = () => {
const location = useLocation();
return <PageImpl key={location.key} />
}
So the idea is: create a wrapper around your page and make React re-create the actual page every time the location key changes.
Now it's enough to call history.push(/this-page-route) again and the page refreshes.
If you want to use <Link/> to reload some route, or simply have single history push, you can setup <Redirect/> route under <Switch/> like this:
<Switch>
<Route exact path="/some-route" component={SomeRoute} />
<Redirect exact from="/some-route/reload" to="/some-route" />
</Switch>
And then <Link to="/some-route/reload" /> or push("/some-route/reload")
If you don't want to reload all scripts again you can replace the current path with a fake/empty path and replace it again with the current path like this
// ...
let currentPath = window.location.pathname;
history.replace('/your-empty-route');
setTimeout(() => {
history.replace(currentPath)
}, 0)
// ...
Update:
If the changing of the address bar bothering, you can add a patterned route like this:
<Route path="/*/reload" component={null}/>
and add /replace to the end of currentPath to replace the router with null component. like this:
// ...
let currentPath = window.location.pathname;
history.replace(`${currentPath}/replace`);
setTimeout(() => {
history.replace(currentPath)
}, 0)
// ...
In this way, the reload keyword will add to the end of your current path and I think it's more user friendly.
Notice: If you already have a route that ends with replace It will cause conflict. To solve that you should change the path of the patterned route to something else.
You could try this workaround:
// I just wanted to reload a /messages page
history.pushState(null, '/');
history.pushState(null, '/messages');
You can use this function.
function reloadPage(){
window.location.reload();
}
<input type="button" onClick={ reloadPage } value="reload"/>
May be you are trying to push in history object, then bind your component with withrouter or use window.location.href = url to redirect ..
With React Router 6 you can simply write :
import {useNavigate} from "react-router-dom";
const navigate = useNavigate()
const goToPageOnClick = () =>{
navigate(target_url)
navigate(0)
}
You can achieve that with React Router v6.
import React from 'react';
import { useNavigation, useLocation } from 'react-router-dom';
const Component = () => {
const history = useNavigation();
const location = useLocation();
const reload = () => {
navigate(location.pathname);
};
return (
...
);
};
and then put your reload function inside a useEffect hook.
PS: but this is a weird question, since react-router reloads the page automatically.
If you are needing an asynchronous reload, use history.go(0) (it wraps the History.go() method).
If you need to reload the page synchronously, use history.push(location.pathname) (it wraps the History.pushState() method).
Since there are already examples here using history.go(0), here's an example using history.push(location.pathname):
import React from 'react';
import { useHistory, useLocation } from 'react-router-dom';
const Component = () => {
const history = useHistory();
const location = useLocation();
const reload = () => {
history.push(location.pathname);
};
return (
...
);
};
update webpacker.yml
devServer: {
historyApiFallback: true,
}
Well, the easiest way is to first identify a route for reload and thereafter call the window.location.reload() function on the route like so:
<Switch>
<Route exact exact path="/" component={SomeComponent} />
<Route path="/reload" render= {(props)=>window.location.reload()} />
</Switch>
I recently had the same problem and created this(https://github.com/skt-t1-byungi/react-router-refreshable).
<Refreshable>
<Switch>
<Route path="/home">
<HomePage />
</Route>
<Route path="/post">
<PostPage />
</Route>
{/* ... */}
</Switch>
</Refreshable>
Related
I want to clear the Google console and I know two ways:
The first one is by use (useEffect).
The second one is by putting the code directly in (return function).
Both ways are shown in the code below, but which one is correct and why?
import { Routes, Route } from "react-router-dom";
import Home from "./routes/home/Home";
import Navigation from "./routes/navigation/Navigation";
import Authentication from "./routes/authentication/Authentication";
import { useEffect } from "react";
const App = () => {
useEffect(() => {
setTimeout(() => console.clear(), 1500);
}, []);
return (
<Routes>
<Route path="/" element={<Navigation />}>
<Route index={true} element={<Home />} />
<Route path="auth" element={<Authentication />} />
</Route>
{setTimeout(() => console.clear(), 1500)}
</Routes>
);
};
export default App;
Using useEffect is the correct way. Here is the explanation:
In React, function components has the same life cycle as class components, as you can see in the image below, they load, render and then something called "componentDidMount" is called:
For code to subscribe, clean, fetch, etc. the optimal way is putting all inside the componentDidMount stage, in function components, this stage is defined as a useEffect without dependencies, as this loads after the component does it's render stage. (you can learn more about it here: https://reactjs.org/docs/hooks-effect.html)
Another thing that you can do is using the "componentWillUnmount" stage, this component's stage is called when is about to disappear, as the result of a navigation or something related to that. So, this should work if you want to clear the console every time the user go to other site page.
In function components, this is called the "cleanup" function:
useEffect(() => {
return () => {
console.clear();
}
});
Hope that helps you :)
<Route path="*">
<Redirect to="/" />
</Route>
The code above is what I am using to handle all not found routes. I have all routes in switch and for the most part this is working fine <Switch>. I was wondering how I would go about sending a windows alert saying something along the lines of "this page doesn't exist" when the unknown route is called. I tried using render and calling a function, but that didn't seem to work. Any thoughts?
edit: to make it clear, I am using React framework, javascript, react-router.
Your current implementation simply redirects back to (/) when the route is not found.
However, to display a window.alert() you should consider making a new NotFound component and handle the display of the alert on that page.
Afterward, use the useHistory hook to redirect back to '/'
See example code below
NotFound Component
import { useEffect } from "react";
import { useHistory } from "react-router-dom";
const NotFound = () => {
let history = useHistory();
useEffect(() => {
window.alert('Page Not found');
history.push('/');
}, []);
return (
<div>404</div>
)
}
export default NotFound;
Existing Routes
<Route path="*">
<NotFound />
</Route>
I have managed to set up Google Analytics for my React application with the ReactGA library so it will send the pageview to analytics when the user navigates around.
The problem
The problem I'm facing is that I'm not sending any analytics to google on the initial page load, since the history.listen method only fires when the location changes.
My setup
In the root of my project, I initialize the connection:
const history = require("history").createBrowserHistory;
import { Router } from "react-router-dom"
ReactGA.initialize(envConstants.ANALYTICS_TRACKING_ID);
const MyApp = () => (
<Router history={history}>
<MyRoutes />
</Router>
)
Since I only want to see which routes the users are on I have this in my router:
const MyRoutes = props => {
props.history.listen(location => {
// won't see this on initial load, but navigating to another route will give me this
console.log("LISTENING")
})
return (...)
}
So I wonder how I can come around this and send the first/ initial pageview when a user comes to my site. I believe I cannot achieve this with the history.listen method. So, I guess we have to add some other functionality that I'm not too sure of.
I appreciate all the help I can get with this. And if there's something unclear, please let me know.
Thanks for reading and have a nice day!
The issue is that history listen is not called on initial page load since it's only called when the location changes. Try something like the following
import { Router } from 'react-router-dom';
import createHistory from 'history/createBrowserHistory';
import ReactGA from 'react-ga';
const trackPageView = location => {
ReactGA.set({ page: location.pathname });
ReactGA.pageview(location.pathname);
};
const initGa = history => {
ReactGA.initialize('UA-XXXXXX-X', {
debug: true
});
trackPageView(history.location);
history.listen(trackPageView);
};
const history = createHistory();
initGa(history);
ReactDOM.render((
<Router history={history}>
<Layout />
</Router>
), document.getElementById('root'));
I was building a search engine for custom project.
There I have a search bar from where user can search.
When the user searches, I want the given link to work as it works in case of google
www.google.com/ search? queryRelatedInfo
Notice the search? and then whatever query/parameter/ID
for this I tried something like this in
import React, {Component} from 'react';
import {
BrowserRouter,
Route,
Switch,
Redirect,
} from 'react-router-dom';
import SearchScreen from "./container/searchScreen.js"
import HomeScreen from "./container/home.js";
class route extends Component {
render () {
return (
<BrowserRouter>
<div>
<Switch>
<Route path ="/" exact render ={(props) => <HomeScreen {...props}/>} />
<Route path ="/search?:id" exact render ={(props) => <SearchScreen {...props}/>} />
</Switch>
</div>
</BrowserRouter>
)
}
}
export default route
Notice, <Route path ="/search?:id" above.
Unfortunately this didn't worked out.
I understand that <Route path ="/:id" works but how can i make <Route path ="/search?:id to work i.e how can I make some link like http://localhost:3000/search?9e9e to work
I think this is related with historyApiFallback. That parameter;
(https://webpack.js.org/configuration/dev-server/#devserver-historyapifallback)
When using the HTML5 History API, the index.html page will likely have to be served in place of any 404 responses. devServer.historyApiFallback is disabled by default. Enable it by passing:
module.exports = {
//...
devServer: {
historyApiFallback: true
}
};
Your react app is a single page application. So all path except home path actually is an virtual path, they are not physically exist. The paths must routed to home path. So react-router can manage.
you don't need to put the path like this /search?:id, just put it search
<Route path ="/search" exact render ={(props) => <SearchScreen {...props}/>} />
then inside your SearchScreen component, get the value of search parameter from the URL, check this issue will help.
after the user make search, pass the value like this /search?s=value_here
I have a universal react app that's using redux and react-router.
I have several routes as follows:
/2016
/2015
/2014
/2013
etc.
Each route requires data from an API. Currently, i have the <Link> elements in the Navigation component dispatch an async action onClick, which populates the store with data from the API for that route.
For MVP, i'm just overwriting the post: {} contents in the store with the new post contents when the route changes, that way we get any new content that was on the API.
I've realise that having the action dispatchers on the <Link> buttons isn't optimal, as hitting the back button does not re-trigger the action dispatch to get the content for the previous route.
Is there a way to get React Router to trigger the dispatch action anytime a route change occurs? (Limiting it to listen to a specific set of routes would be a bonus).
I realise i should be getting the history from the store, but for now, it's easier to hit the API again by triggering an action dispatch in order to get the new content.
Cheers.
The 'lifecycle' hook onEnter and onChange has been removed in React-router 4 which makes most of the other answers to this question out-dated.
Whilst I recommend you to use your components lifecycle methods to achieve your goal, here is an answer to your question which works on React-router 4.
What works today is listen to the history change using History library created by the developers of React router themself and dispatch async actions from there.
// history.js
import createHistory from "history/createBrowserHistory"
const history = createHistory()
// Get the current location.
const location = history.location
// Listen for changes to the current location.
const unlisten = history.listen((location, action) => {
//Do your logic here and dispatch if needed
})
export default history
Then import the history in your application
// App.js
import { Router, Route } from 'react-router-dom';
import Home from './components/Home';
import Login from './components/Login';
import history from './history';
class App extends Component {
render() {
return (
<Router history={history}>
<div>
<Route exact path="/" component={Home} />
<Route path="/login" component={Login} />
</div>
</Router>
)
}
}
Source: History library
React router docs
Yeah React Router has onEnter and onLeave hooks. You could build your routes to take your store instance, so you can access it in those helpers:
const createRoutes = (store) => {
const fetchPosts = () => store.dispatch({
types: ['FETCH_POSTS', 'FETCH_POSTS_SUCCESS', 'FETCH_POSTS_FAIL',
url: '/posts'
});
return (
<Route path="/" component={App}>
<Route path="posts" component={PostList} onEnter={fetchPosts}/>
<Route path="posts/:id" component={PostDetail} />
</Route>
)
}
A better solution is to use something like redial or redux-async-connect. This allows you to co-locate your component's data dependencies with your components, while retaining the ability to test your components without touching the network.
Edit: This applies to an old, no longer supported version of react-router.
I prefer to have actions dispatched from the render prop itself:
<Route to="path" render={ props => {
this.props.toggleInfoLayer(true);
return <UserInfo />;
}} />
This is assuming you are using Redux's mapDispatchToProps argument.
I tried using the history change event handler as mentioned in the accepted answer, but I found it undesirable to be dispatching actions from a rogue file. One more place I had to think about, when Redux already provides plenty too many.