The new version of React, React 16.8 was released this month - and it finally has Hooks.
From the official announcement:
Hooks let you use state and other React features without writing a class. You can also build your own Hooks to share reusable stateful logic between components.
Today I began refactoring my React URL Shortener to using Hooks instead of class components.
The app has a simple form input where you can type in a URL. Submitting the form triggers an API call to the Rebrandly API which shortens the URL.
Originally the Inputform
component held its own state. I wanted to avoid triggering a rerendering of the app whenever the user changes the input field.
import React from "react";
import PropTypes from "prop-types";
class Inputform extends React.Component {
static propTypes = {
onSubmit: PropTypes.func.isRequired
};
state = { inputUrl: "" };
onInputChange = event => {
event.preventDefault();
const value = event.target.value;
this.setState({ inputUrl: value });
};
onSubmit = event => {
event.preventDefault();
this.props.onSubmit({ inputUrl: this.state.inputUrl });
};
render() {
const { inputUrl } = this.state;
return (
<form className="black-80 tc pv3" onSubmit={this.onSubmit}>
<label className="f4 dib mb2">
URL to be shortened:
<input
id="url-shortener-input"
className="input-reset ma2 mb2 pa2 ba b--black-20"
placeholder="https://example.com"
type="text"
aria-describedby="url-shortener-input-desc"
value={inputUrl}
onChange={this.onInputChange}
/>
<button
id="url-shortener-input-desc"
className="fw-30 f6 shadow-5 b--transparent grow br-pill ph3 pv2 mb2 dib white bg-dark-red"
type="submit"
disabled={!inputUrl}
>
Shorten
</button>
</label>
</form>
);
}
}
export default Inputform;
I used this blog post to refactor the app: Using Custom React Hooks to Simplify Forms.
First, I created a new file with a helper function:
import { useState } from "react";
const useForm = callback => {
const [values, setValues] = useState({});
const handleSubmit = event => {
if (event) event.preventDefault();
callback(values);
};
const handleChange = event => {
event.persist();
setValues(values => ({
...values,
[event.target.name]: event.target.value
}));
};
return {
handleChange,
handleSubmit,
values
};
};
export default useForm;
This is almost the same code as in the blog example. The useForm
function takes a callback function as an argument and sets up the Hook useState
tuple with [values, setValues]
. It also defines a handleSubmit
function and a handleChange
function.
In the handleSubmit
function, I made sure to pass the values to the callback function as an argument. This way, the values can be passed to other components.
Now Inputform.js
looks like this:
import React from "react";
import PropTypes from "prop-types";
import useForm from "../helpers/useform";
const Inputform = ({ onSubmit }) => {
const { values, handleChange, handleSubmit } = useForm(onSubmit);
return (
<form className="black-80 tc pv3" onSubmit={handleSubmit}>
<label className="f4 dib mb2">
URL to be shortened:
<input
id="url-shortener-input"
name="inputUrl"
className="input-reset ma2 mb2 pa2 ba b--black-20"
placeholder="https://example.com"
type="text"
aria-describedby="url-shortener-input-desc"
value={values.text}
onChange={handleChange}
/>
<button
id="url-shortener-input-desc"
className="fw-30 f6 shadow-5 b--transparent grow br-pill ph3 pv2 mb2 dib white bg-dark-red"
type="submit"
disabled={!values.inputUrl}
>
Shorten
</button>
</label>
</form>
);
};
Inputform.propTypes = {
onSubmit: PropTypes.func.isRequired
};
export default Inputform;
It’s not a React class component anymore but a stateless functional component. It imports the useForm
helper and uses the function to handle state.
The Inputform
function receives an onSubmit
function from its parent component. This function is ultimately responsible for calling the API. But the Hook handles all the changes to the input form and the baton change to onSubmit
. The Inputform is now a “dumb” component and doesn’t know anything about state.
Further Reading
- React Documentation: Hooks
- Using Custom React Hooks to Simplify Forms by James King
- What are React Hooks? by Robin Wieruch
- How to fetch data with React Hooks? by Robin Wieruch