API. Both APIs offer the same functionality but usage is completely different.
history.push
With the newer versions of React Router, you’re able to get access the history
API with hooks.
import React from "react";
import { useHistory } from "react-router-dom";
import { signIn } from "~/api";
import SignInForm from "./SignInForm";
const SignIn = () => {
const history = useHistory();
const [hasError, setError] = React.useState(null);
const handleSignIn = async (username, password) => {
try {
await signIn(username, password);
history.push("/dashboard");
} catch (error) {
setError(true);
}
};
return <SignInForm onSubmit={handleSignIn} hasError={hasError} />;
};
export default SignIn;
While this code is very much simplified, you have to look carefully to find the place where the redirect takes place. The manner we use the history.push
API here is called imperative. With imperative programming you define how to do something - step by step. But recently, we see that declarative programming is more trendy. Instead of defining how to log step by step, we just tell the computer what we want. By applying declarative programming pattern, we create clearer boundaries in our applications. Let’s see how this sign-in example would look like with the declarative <Redirect />
API:
import React from "react";
import { Redirect } from "react-router-dom";
import { signIn } from "~/api";
import SignInForm from "./SignInForm";
const SignInState = Object.freeze({
LoggedOut: 0,
LoggedIn: 1,
Failed: 2,
});
const SignIn = () => {
const [signInState, setSignInState] = React.useState(SignInState.LoggedOut);
const handleSignIn = async (username, password) => {
try {
await signIn(username, password);
setSignInState(SignInState.LoggedIn);
} catch (error) {
setSignInState(SignInState.Failed);
}
};
if (signInState === SignInState.LoggedIn) {
return <Redirect push to="/dashboard" />;
}
return (
<SignInForm
onSubmit={handleSignIn}
hasError={signInState === SignInState.Failed}
/>
);
};
export default SignIn;
While this example is way bigger, it has a big benefit: It’s easier to see how the API will behave. It gives also the opportunity to change the behaviour later more easily as the action is now decoupled from the side effect.
Written by Elmar Burke who lives and works in Amsterdam building useful things. You can follow them on the fediverse