Refactor a form with React Hooks and useState
Tags: react, hooks
Published: 2019-03-02 09:56:27

---
title: Refactor a form with React Hooks and useState
published: true
description: To learn, start small
tags: react, hooks
---

## Introduction

React Hooks are one of those things I decided I would look at *later*. I've read and heard great things about it, so I later is now. I had a component with a form that I thought could be refactored using hooks, so I started with that. Always easier to begin with small steps.

## Before

Nothing fancy, we use the *material-ui* framework to create a Dialog component. Then we have three TextFields ( text inputs ) inside of it:

```javascript

export default class AddItemPopup extends React.Component {

	constructor(props){
		super(props)
		this.state = {
			name: '',
			quantity: 0,
			unitCost: 0
		}
	}

	handleInputChange = e => {
		const {name, value} = e.target
		this.setState({
			[name]: value
		})
	}

	addItem = () => {
		const {name, quantity, unitCost} = this.state

		if(!name || !quantity || !unitCost) return
	
		this.props.saveItem(this.state)
	}

	render(){

		const {open, closePopup} = this.props
		const {name, quantity, unitCost} = this.state
		return(
			<Dialog 
				open={open}
				onClose={closePopup}>
				<DialogTitle>Add new item</DialogTitle>
				<DialogContent>
					<TextField 
						name='name'
						label='Item name/Description'
						onChange={this.handleInputChange}
						value={name}/>
					<TextField 
						name='quantity'
						label='Quantity'
						onChange={this.handleInputChange}
						value={quantity}/>
					<TextField 
						name='unitCost'
						label='Unit Cost'
						onChange={this.handleInputChange}
						value={unitCost}/>
				</DialogContent>
				<DialogActions>
					<Button onClick={closePopup} color="secondary" variant="contained">
						Cancel
					</Button>
					<Button onClick={this.addItem} color="primary" variant="contained">
							Save
					</Button>
				</DialogActions>
			</Dialog>
		)
	}
}
```

I saved you the imports at the top of the file, but you got the idea. A class component with a form and a state to keep track of the form inputs' values. Now, let's rewrite this component by using the useState hook.

```javascript
// Import the hook first
import React, {useState} from 'react'

const AddItemPopup = ({
	open, 
	closePopup,
	saveItem
}) => {

	const handleInputChange = e => {
		const {name, value} = e.target
		setValues({...values, [name]: value})
	}
	
	const addItem = () => {
		const {name, quantity, unitCost} = values

		if(!name || !quantity || !unitCost) return
		
		saveItem(values)
	}
        // Declare our state variable called values
        // Initialize with our default values

	const [values, setValues] = useState({name: '', quantity: 0, unitCost: 0})
	return(
		<Dialog 
		open={open}
		onClose={closePopup}>
		<DialogTitle>Add new item</DialogTitle>
			<DialogContent>
				<TextField 
					name='name'
					label='Item name/Description'
					onChange={handleInputChange}
					value={values.name}/>
				<TextField 
					name='quantity'
					label='Quantity'
					onChange={handleInputChange}
					value={values.quantity}/>
				<TextField 
					name='unitCost'
					label='Unit Cost'
					onChange={handleInputChange}
					value={values.unitCost}/>
			</DialogContent>
			<DialogActions>
				<Button onClick={closePopup} color="secondary" variant="contained">
					Cancel
				</Button>
				<Button onClick={addItem} color="primary" variant="contained">
						Save
				</Button>
			</DialogActions>
		</Dialog>
	)
}

export default AddItemPopup
```

BOOM! Our component became a function now. What did we do:

- *useState* returns two things: the current state ( here as *values* ) and a function that lets you update it ( here as *setValues* )
- *useState* takes one argument: the initial state.
- The onChange handler function now uses this *setValues* function to modify the internal state of the component. As you can see, the *values* variable is accessible everywhere is the component.

*Note*: We could have used three different hooks to update each input separately, whatever you think might be more readable to you ;)