React-Router: Programmatic Navigation
GitHub Repos
Intro
If we consider navigation when a user clicks on links to be Intentional Navigation, we are now going to look at Programmatic Navigation, where we force the application to navigate to a new location based on a set of triggers, like form submission.
We will be learning this within the context of our Twitch Clone application called "Glitch"
The question of when to programmatically navigate the user is an important one, and will be context specific. In this example we will be re-routing the user after they have successfully created a stream in our Twitch Clone. Therefore we want to wait until we have received a successful status code from the server before we re-route the user. Some flash messages would be helpful also, but we will be getting into those at a later time.
In this case, in my current opinion, the best way to accomplish this would be to use the React Router Redirect component, which is built for just this purpose.
If we combine that with all of the props that are available to us thanks to Redux-Form, we can take advantage of the submitSucceeded
prop and implement this re-direct quite easily.
import React, { Component } from "react";
import { Field, reduxForm } from "redux-form";
import { connect } from "react-redux";
import { Redirect } from "react-router-dom";
import { createStream } from "../../actions";
class StreamCreate extends Component {
renderError({ error, touched }) {
if (touched && error) {
return <div className="ui pointing label">{error}</div>;
}
}
// must be arrow function so that context of this is bound for this.renderError
renderInput = ({ input, label, meta }) => {
return (
<div className="field">
<label>{label}</label>
<input {...input} />
{this.renderError(meta)}
</div>
);
};
// send post request to api server on submit
onSubmit = (formValues) => {
this.props.createStream(formValues);
};
render() {
// check for successful form submission
// redirect to index if true
if (this.props.submitSucceeded === true) {
return <Redirect to="/" />;
}
return (
<form
className="ui form"
onSubmit={this.props.handleSubmit(this.onSubmit)}
>
<Field
name="title"
component={this.renderInput}
label="Enter Title: "
/>
<Field
name="description"
component={this.renderInput}
label="Enter Description: "
/>
<button className="ui button primary">Submit</button>
</form>
);
}
}
const validate = (formValues) => {
const errors = {};
if (!formValues.title) {
errors.title = "You must enter a title";
}
if (!formValues.description) {
errors.description = "You must enter a description";
}
return errors;
};
// form wrapper
const formWrapped = reduxForm({
form: "createStream",
validate: validate,
})(StreamCreate);
// redux connect
export default connect(null, { createStream })(formWrapped);
It is worth noting however that there is disagreement on this issue. There is one school of thought that you should accomplish this by messing with the React-Router History.
There is a good article that discusses the difference between the two methods here.
It seems to me that manipulating the history is a "hacky" way of accomplishing this, and is not preferable in newer versions.
Comments
Recent Work
Basalt
basalt.softwareFree desktop AI Chat client, designed for developers and businesses. Unlocks advanced model settings only available in the API. Includes quality of life features like custom syntax highlighting.
BidBear
bidbear.ioBidbear is a report automation tool. It downloads Amazon Seller and Advertising reports, daily, to a private database. It then merges and formats the data into beautiful, on demand, exportable performance reports.