Component is not getting rendered after history.push()
You're creating new history each time you invoke createHistory()
. If you're using react-router-dom
you can simply use the withRouter
HOC that'll supply the history
object to the component via a prop
. You'll then utilize history.push('/')
, or if it's in a class component
, this.props.history.push('/')
and so on.
Working example: https://codesandbox.io/s/p694ln9j0
routes (define history
within routes
)
import React from "react";
import { Router, Route, Switch } from "react-router-dom";
import { createBrowserHistory } from "history";
import Header from "../components/Header";
import Home from "../components/Home";
import About from "../components/About";
import Contact from "../components/Contact";
import ScrollIntoView from "../components/ScrollIntoView";
const history = createBrowserHistory();
export default () => (
<Router history={history}>
<div>
<ScrollIntoView>
<Header />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
</Switch>
<Header />
</ScrollIntoView>
</div>
</Router>
);
components/Header.js (we want to access history
, however, sometimes we have to use withRouter
because components like Header
don't reside within a <Route "/example" component={Header}/>
HOC, so it's unaware of our routing)
import React from "react";
import { withRouter } from "react-router-dom";
const Header = ({ history }) => (
<header>
<nav style={{ textAlign: "center" }}>
<ul style={{ listStyleType: "none" }}>
<li style={{ display: "inline", marginRight: 20 }}>
<button onClick={() => history.push("/")}>Home</button>
</li>
<li style={{ display: "inline", marginRight: 20 }}>
<button onClick={() => history.push("/about")}>About</button>
</li>
<li style={{ display: "inline", marginRight: 20 }}>
<button onClick={() => history.push("/contact")}>Contact</button>
</li>
</ul>
</nav>
</header>
);
export default withRouter(Header);
components/Home.js (a component like Home
is aware of routing and has the history
object already passed in via the <Route path="/" component={Home} />
HOC, so withRouter
isn't required)
import React from "react";
const Home = ({ history }) => (
<div className="container">
<button
className="uk-button uk-button-danger"
onClick={() => history.push("/notfound")}
>
Not Found
</button>
<p>
...
</p>
</div>
);
export default Home;
Same concept as above, however, if you don't want to use withRouter
, then you can simply create a history
instance that'll be shared across your components that need it. You'll import
this history
instance and navigate with history.push('/');
and so on.
Working example: https://codesandbox.io/s/5ymj657k1k
history (define history
in its own file)
import { createBrowserHistory } from "history";
const history = createBrowserHistory();
export default history;
routes (import history
into routes
)
import React from "react";
import { Router, Route, Switch } from "react-router-dom";
import Header from "../components/Header";
import Home from "../components/Home";
import About from "../components/About";
import Contact from "../components/Contact";
import ScrollIntoView from "../components/ScrollIntoView";
import history from "../history";
export default () => (
<Router history={history}>
<div>
<ScrollIntoView>
<Header />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
</Switch>
<Header />
</ScrollIntoView>
</div>
</Router>
);
components/Header.js (import history
into Header
)
import React from "react";
import history from "../history";
const Header = () => (
<header>
<nav style={{ textAlign: "center" }}>
<ul style={{ listStyleType: "none" }}>
<li style={{ display: "inline", marginRight: 20 }}>
<button onClick={() => history.push("/")}>Home</button>
</li>
<li style={{ display: "inline", marginRight: 20 }}>
<button onClick={() => history.push("/about")}>About</button>
</li>
<li style={{ display: "inline", marginRight: 20 }}>
<button onClick={() => history.push("/contact")}>Contact</button>
</li>
</ul>
</nav>
</header>
);
export default Header;
components/Home.js (is still aware of routing and has the history
object already passed in via the <Route path="/" component={Home} />
HOC, so importing history
isn't required, but you can still import it if you wanted to -- just don't deconstruct history
in the Home
's function parameters)
import React from "react";
const Home = ({ history }) => (
<div className="container">
<button
className="uk-button uk-button-danger"
onClick={() => history.push("/notfound")}
>
Not Found
</button>
<p>
...
</p>
</div>
);
export default Home;
But you might be thinking, what about BrowserRouter
? Well, BrowserRouter
has it's own internal history
object. We can, once again, use withRouter
to access its history
. In this case, we don't even need to createHistory()
at all!
Working example: https://codesandbox.io/s/ko8pkzvx0o
routes
import React from "react";
import { BrowserRouter, Route, Switch } from "react-router-dom";
import Header from "../components/Header";
import Home from "../components/Home";
import About from "../components/About";
import Contact from "../components/Contact";
import Notfound from "../components/Notfound";
import ScrollIntoView from "../components/ScrollIntoView";
export default () => (
<BrowserRouter>
<div>
<ScrollIntoView>
<Header />
<Switch>
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/contact" component={Contact} />
<Route component={Notfound} />
</Switch>
<Header />
</ScrollIntoView>
</div>
</BrowserRouter>
);
React router dom v5 history.push does not render new page
Issue
You are submitting the form but not preventing the default form action from occurring. This reloads the page before the POST request response can be handled and the UI redirected.
Solution
Move the onClick={signIn}
to the Form
component and switch it to the onSubmit
handler, and in the signin
handler consume the onSubmit
event object and prevent the default form action.
function SignIn() {
const history = useHistory();
const [userEmail, setEmail] = useState("");
const [userPassword, setPassword] = useState("");
//after onClick
const signIn = (e) => { // <-- onSubmit event object
e.preventDefault(); // <-- preventDefault
// get user input
Axios.post("http://localhost:8800/signIn", {
userEmail: userEmail,
userPassword: userPassword
}).then((res) => {
console.log(res);
history.push("/clientprofile");
});
};
return (
<Form onSubmit={signIn}> // <-- onSubmit event handler
...
<Button variant="primary" type="submit"> // <-- remove onClick handler
Submit
</Button>
</Form>
);
}
React history.push() not rendering new component
If anyone is interested - this was happening because the app was rendering before the history was pushed. When I put the history push into my action but just before the result is converted into JSON, it started working since now it pushes history and only then renders the App.
export const authorization = (username, password, history) => (dispatch) =>
new Promise ((resolve, reject) => {
fetch(url, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({
username: username,
password: password,
})
}).then( response => {
if (response.ok) {
//################################
//This is where I put it
history.push("/servers");
//################################
response.json().then( result => {
dispatch(logUserIn(result.token));
resolve(result);
})
} else {
let error = new Error(response.statusText)
error.response = response
dispatch(showError(error.response.statusText), () => {throw error})
reject(error);
}
});
});
history.push changes url, but component is not rendered
Issue
You are creating a custom history object that your BrowserRouter
doesn't know about. The LoginForm
component is manipulating one version of a history
object while the router and routes are using the default history
object used by the routing context. The login form is able to update the URL in the address bar but the outer routing context isn't able to see this change.
Solution
Either remove the custom history and use the one provided by BrowsserRouter
or or use the lower level Router
component and pass the custom history
object to it to be used in the routing context.
Use standard history from routing context
Router.js
<BrowserRouter >
<LoginForm/>
<Switch>
<Route path="/dashboard" component={Dashboard}/>
</Switch>
</BrowserRouter>
LoginForm - decorate with the withRouter
higher order component so it receives route props from the closest routing context.
import React, {Component} from "react";
import { withRouter } from 'react-router-dom';
class LoginForm extends Component {
handleSubmit = (event) => {
event.preventDefault()
this.props.history.push("/dashboard")
}
render() {
return (
<form name="signup_form" onSubmit={this.handleSubmit}>
<input type="submit" value="Sign Up"/>
</form>
);
}
}
export default withRouter(LoginForm);
Use custom history
import LoginForm from "./LoginForm";
import { Router, Route, Switch } from "react-router-dom";
import React, { Component } from "react";
import { createBrowserHistory } from "history"
const browserHistory = createBrowserHistory()
class MyRouter extends Component {
render() {
return (
<Router history={browserHistory} >
<LoginForm />
<Switch>
<Route path="/dashboard" component={Dashboard}/>
</Switch>
</Router>
)
}
}
export default MyRouter;
And still decorate LoginForm
with the withRouter
HOC so the route props are passed.
import React, {Component} from "react";
import { withRouter } from 'react-router-dom';
class LoginForm extends Component {
handleSubmit = (event) => {
event.preventDefault()
this.props.history.push("/dashboard")
}
render() {
return (
<form name="signup_form" onSubmit={this.handleSubmit}>
<input type="submit" value="Sign Up"/>
</form>
);
}
}
export default withRouter(LoginForm);
Suggestion
As written, the LoginForm
component will always be rendered, this is probably not what you intended. I suggest just moving it into a route so the route props will be passed.
<Route path="/login" component={LoginForm} />
React Router history.push() changed url but did not rendered components content
You need hook useHistory
from 'react-router-dom' but not from package 'history'
import { useHistory } from 'react-router-dom'
const history = useHistory();
history.push(...);
React router not rendering the component through history.push()
Try this
import { React } from "react";
import { Router as MyRouter, Switch, Route } from "react-router-dom";
import NavBar from "./Components/NavBar";
import Article from "./Components/Article";
import Articles from "./Components/Articles";
const Router = () => {
return (
<div>
<MyRouter >
<NavBar />
<Switch>
<Route exact path="/" component={Articles} />
<Route exact path="/home/:title/:id" component={Article} />
</Switch>
</MyRouter>
</div>
);
};
Since you are using Router
as a wrapper of your application, what if you don't pass the history
object on the Router
since you will be using the react hook useHistory()
.
Related Topics
How to Add Spaces to for Loop Output in JavaScript
Postman Test - Validating String Values in an Object in an Array
Pass Variable from Android to JavaScript Launched in Webview
How to Hide Blinking Cursor in Input Text
How to Store Multiple Items in Local Storage
Using Setstate to Change Multiple Values Within an Array of Objects - Reactjs
Show Form Fields Based on Selected Option
Reinitialize Slick Js After Successful Ajax Call
Calculating Sum of Checked Checkboxes
Weird Behaviour With on Click Event Binding; Event Not Firing
How to Tell If a Dom Element Is Visible in the Current Viewport
Parsing Error: Unexpected Token, Expected ","
How to Pass Checkbox State to Onclick Function in React
Generate and Download CSV File With PHP and Ajax
Reactjs How to Call a Component Function from Another Function on the Same File
Datatables/Tabletools: Format Data as Text When Exporting to Excel
How to Retrieve Value in Input Checkbox (Using Reactjs)
How to Check If Prevprops and Nextprops Are the Same in React