Enhance Your React App With Undo and Reset Abilities
Tags: react, javascript, node, webdev
Published: 2019-06-24 16:31:48

Find me on [medium](https://medium.com/@jsmanifest)

Ever developed something where you made mistakes and wished there was an _undo_ feature? What about _reset_?

Luckily there is always undo or reset capabilities in software we use. I'm talking _ctrl + z_ in [vscode](https://code.visualstudio.com/), or commonly in the 90s a _reset_ button in forms.

Why do we even need them? Well, because humans _always_ make mistakes. Whether it is a typo or wrong wording in a written essay, we need _some way_ to undo something. When you think about it though, there are ways to undo something almost _everywhere_. Pencils have erasers, phones have capabilities to be taken apart, users are given the option to reset their passwords, erasable pens rubbing their ink away--the list goes on.

But what about implementing an undo or reset feature _as a developer_ for an application? Where do you start? Where should you look for advice?

Well, look no further because I am here to show you how to enhance your application with _undo_ and _reset_ capabilities! You will find out from this article that it isn't that hard to implement and _you can do it too_.

What we'll be building is a user interface where users are able to add their friends by name and specifying their friend's gender. As friends are inserted, cards will be appended to the screen displaying the information the friend was registered with. In addition, if their friend is a female it will be displayed with a _hotpink_ colored borderline, while the males will have a _teal_ borderline. If the user made a mistake when registering the friend, he or she may choose to _undo_ that action or _reset_ the entire interface back to its beginning state. And finally, they will be able to change their interface theme color in case they like dark over light, or vice versa.

Here is what that will look like:

## Light

![final light](https://jsmanifest.s3-us-west-1.amazonaws.com/posts/enhance-your-react-app-with-undo-reset-abilities/final-light.jpg)

## Dark

![final dark](https://jsmanifest.s3-us-west-1.amazonaws.com/posts/enhance-your-react-app-with-undo-reset-abilities/final-dark.jpg)

Without further ado, let's begin!

In this tutorial we are going to quickly generate a react project with create-react-app.

(If you want to get a copy of the repository from github, click [here](https://github.com/jsmanifest/undo-reset)).

Go ahead and create a project using the command below. For this tutorial i’ll call our project _undo-reset_.

```bash
npx create-react-app undo-reset
```

Now go into the directory once it's done:

```bash
cd undo-reset
```

Inside the main entry `src/index.js` we're going to clean it up a bit:

> src/index.js

```jsx
import React from 'react'
import ReactDOM from 'react-dom'
import App from './App'
import './styles.css'
import * as serviceWorker from './serviceWorker'

ReactDOM.render(<App />, document.getElementById('root'))
serviceWorker.unregister()
```

Here are the starting styles:

src/styles.css

```css
body {
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto',
    'Oxygen', 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans',
    'Helvetica Neue', sans-serif;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}
```

Now create `src/App.js`. This will render all the components we'll be building throughout the tutorial:

src/App.js

```jsx
import React, { useState } from 'react'

const App = () => {
  const [name, setName] = useState('')
  const [gender, setGender] = useState('Male')
  const onNameChange = (e) => setName(e.target.value)
  const onGenderChange = (e) => setGender(e.target.value)

  return <div />
}

export default App
```

Since we'll be letting the user add their friends and specifying the names and genders, we defined a couple of react hooks to hold the input values and we'll also define the methods to update them.

We'll then implement the elements and input fields that the hooks will attach themselves to:

src/App.js

```jsx
const App = () => {
  const [name, setName] = useState('')
  const [gender, setGender] = useState('Male')
  const onNameChange = (e) => setName(e.target.value)
  const onGenderChange = (e) => setGender(e.target.value)

  return (
    <div>
      <form className="form">
        <div>
          <input
            onChange={onNameChange}
            value={name}
            type="text"
            name="name"
            placeholder="Friend's Name"
          />
        </div>
        <div>
          <select onChange={onGenderChange} name="gender" value={gender}>
            <option value="Male">Male</option>
            <option value="Female">Female</option>
            <option value="Other">Other</option>
          </select>
        </div>
        <div>
          <button type="submit">Add</button>
        </div>
      </form>
    </div>
  )
}
```

src/styles.css

```css
form {
  display: flex;
  align-items: center;
}

form > div {
  margin: auto 3px;
}

input,
select {
  transition: all 0.15s ease-out;
  border: 1px solid #ddd;
  padding: 10px 14px;
  outline: none;
  font-size: 14px;
  color: #666;
}

input:hover,
select:hover {
  border: 1px solid #c6279f;
}

select {
  cursor: pointer;
  padding-top: 9px;
  padding-bottom: 9px;
}

button {
  transition: all 0.15s ease-out;
  background: #145269;
  border: 1px solid #ddd;
  padding: 10px 35px;
  outline: none;
  cursor: pointer;
  color: #fff;
}

button:hover {
  color: #145269;
  background: #fff;
  border: 1px solid #145269;
}

button:active {
  background: rgb(27, 71, 110);
  border: 1px solid #a1a1a1;
  color: #fff;
}
```

Now I don't like to keep my interface super plain in my tutorials--after all, I _do_ value your time put into reading my posts, so I provided some thought into the styles to keep you away from boredom :)

Next, we need a solid place to put the undo and reset logic in, so we'll create a custom hook that will handle state updates:

src/useApp.js

```jsx
const useApp = () => {
  const onSubmit = (e) => {
    e.preventDefault()
    console.log('Submitted')
  }

  return {
    onSubmit,
  }
}

export default useApp
```

The _onSubmit_ above is going to be passed into the _form_ we defined earlier, which will help append friends to the friends list when the user submits them:

src/App.js

```jsx
import React, { useState } from 'react'
import useApp from './useApp'

const App = () => {
  const { onSubmit } = useApp()

  const [name, setName] = useState('')
  const [gender, setGender] = useState('Male')
  const onNameChange = (e) => setName(e.target.value)
  const onGenderChange = (e) => setGender(e.target.value)

  return (
    <div>
      <form className="form" onSubmit={onSubmit({ name, gender })}>
        <div>
          <input
            onChange={onNameChange}
            value={name}
            type="text"
            name="name"
            placeholder="Friend's Name"
          />
        </div>
        <div>
          <select onChange={onGenderChange} name="gender" value={gender}>
            <option value="Male">Male</option>
            <option value="Female">Female</option>
            <option value="Other">Other</option>
          </select>
        </div>
        <div>
          <button type="submit">Add</button>
        </div>
      </form>
    </div>
  )
}

export default App
```

Something to note here is that _onSubmit_ is given the field parameters as arguments. If we look back at our _onSubmit_ handler it isn't a [higher order function](https://codeburst.io/here-are-7-ways-higher-order-functions-can-improve-your-life-a392aa6b29d2). That means it will become invoked immediately as the component mounts, so we need to convert the onSubmit handler to be a higher order function to bypass that as well as giving it the ability to receive the values of the fields:

src/useApp.js

```jsx
const useApp = () => {
  const onSubmit = (friend) => (e) => {
    e.preventDefault()
    console.log(friend)
  }

  return {
    onSubmit,
  }
}

export default useApp
```

So far, we have this:

![](https://jsmanifest.s3-us-west-1.amazonaws.com/posts/enhance-your-react-app-with-undo-reset-abilities/1.gif)

Next we'll start implementing the logic. But first, we need to define the _state structure_:

src/useApp.js

```jsx
const initialState = {
  friends: [],
  history: [],
}
```

The most important part of this tutorial is _history_. When the user submits an action, we're going to _capture_ the state of the app and safely store it in a place where we can reference later to undo user actions. This _"storage"_ is _state.history_ which _only_ our custom hook needs to know about. However, it can also be used in the user interface for interesting functionality--like allowing the user to view their previous actions through a grid and _choosing_ which one to go back to. That is a handy little feature to _wow_ your users!

Next, we're going to add the switch cases in the reducer so that our state can actually update:

src/useApp.js

```jsx
const reducer = (state, action) => {
  switch (action.type) {
    case 'add-friend':
      return {
        ...state,
        friends: [...state.friends, action.friend],
        history: [...state.history, state],
      }
    case 'undo': {
      const isEmpty = !state.history.length
      if (isEmpty) return state
      return { ...state.history[state.history.length - 1] }
    }
    default:
      return state
  }
}
```

When we _dispatch_ an action with type _'add-friend'_, we went ahead and added the new friend to the list. But what the _user doesn't know_ is that we are _silently saving their previous edits_. We captured the most recent state of the app and saved it in the _history_ array. This way, if the user ever wants to come back to a previous state we can help them make that happen :)

Since we're using a react hook api, we musn't forget to import it from _react_. We also need to define the _useReducer_ implementation inside our custom hook so that we acquire the api to send signals to update our local state:

src/useApp.js

```jsx
import { useReducer } from 'react'

// ... further down inside the custom hook:
const [state, dispatch] = useReducer(reducer, initialState)
```

Now that we acquired the apis, let's incorporate them to places that need it:

src/useApp.js

```jsx
const onSubmit = (friend) => (e) => {
  e.preventDefault()
  if (!friend.name) return
  dispatch({ type: 'add-friend', friend })
}

const undo = () => {
  dispatch({ type: 'undo' })
}
```

Here's what our custom hook looks like so far:

src/useApp.js

```jsx
import { useReducer } from 'react'

const initialState = {
  friends: [],
  history: [],
}

const reducer = (state, action) => {
  switch (action.type) {
    case 'add-friend':
      return {
        ...state,
        friends: [...state.friends, action.friend],
        history: [...state.history, state],
      }
    case 'undo': {
      const isEmpty = !state.history.length
      if (isEmpty) return state
      return { ...state.history[state.history.length - 1] }
    }
    default:
      return state
  }
}

const useApp = () => {
  const [state, dispatch] = useReducer(reducer, initialState)

  const onSubmit = (friend) => (e) => {
    e.preventDefault()
    if (!friend.name) return
    dispatch({ type: 'add-friend', friend })
  }

  const undo = () => {
    dispatch({ type: 'undo' })
  }

  return {
    ...state,
    onSubmit,
    undo,
  }
}

export default useApp
```

Next, we're going to need to render the list of friends that are inserted into _state.friends_ so that the user can see them in the interface:

src/App.js

```jsx
const App = () => {
  const { onSubmit, friends } = useApp()

  const [name, setName] = useState('')
  const [gender, setGender] = useState('Male')
  const onNameChange = (e) => setName(e.target.value)
  const onGenderChange = (e) => setGender(e.target.value)

  return (
    <div>
      <form className="form" onSubmit={onSubmit({ name, gender })}>
        <div>
          <input
            onChange={onNameChange}
            value={name}
            type="text"
            name="name"
            placeholder="Friend's Name"
          />
        </div>
        <div>
          <select onChange={onGenderChange} name="gender" value={gender}>
            <option value="Male">Male</option>
            <option value="Female">Female</option>
            <option value="Other">Other</option>
          </select>
        </div>
        <div>
          <button type="submit">Add</button>
        </div>
      </form>
      <div className="boxes">
        {friends.map(({ name, gender }, index) => (
          <FriendBox key={`friend_${index}`} gender={gender}>
            <div className="box-name">Name: {name}</div>
            <div className="gender-container">
              <img src={gender === 'Female' ? female : male} alt="" />
            </div>
          </FriendBox>
        ))}
      </div>
    </div>
  )
}
```

If you're wondering what this odd line is doing:

```jsx
<img src={gender === 'Female' ? female : male} alt="" />
```

I actually just provided my own images to render on the _img_ element in order to easily differentiate between a _female_ and _male_ in the interface--for demonstration purposes. Those of you who are cloning the repository will be able to see them in the _src/images_ directory if you need a copy of them :)

We import the female/male images at the top of _App.js_, and right above the _App_ component we'll define a _FriendBox_ component which will be responsible for rendering a _friend_ box as the user adds to them to the list:

src/App.js

```jsx
// At the top
import female from './images/female.jpg'
import male from './images/male.jpg'

// Somewhere above the App component
const FriendBox = ({ gender, ...props }) => (
  <div
    className={cx('box', {
      'teal-border': gender === 'Male',
      'hotpink-border': gender === 'Female',
    })}
    {...props}
  />
)
```

In order to further differentiate between a _female_ and _male_ in a visual perspective, I additionally added in basic styles to represent each:

src/styles.css

```css
.teal-border {
  border: 1px solid #467b8f;
}

.hotpink-border {
  border: 1px solid #c1247d;
}
```

And here is what we have so far for the _App.js_ file:

src/App.js

```jsx
import React, { useState } from 'react'
import cx from 'classnames'
import female from './images/female.jpg'
import male from './images/male.jpg'
import useApp from './useApp'

const FriendBox = ({ gender, ...props }) => (
  <div
    className={cx('box', {
      'teal-border': gender === 'Male',
      'hotpink-border': gender === 'Female',
    })}
    {...props}
  />
)

const App = () => {
  const { onSubmit, friends } = useApp()

  const [name, setName] = useState('')
  const [gender, setGender] = useState('Male')
  const onNameChange = (e) => setName(e.target.value)
  const onGenderChange = (e) => setGender(e.target.value)

  return (
    <div>
      <form className="form" onSubmit={onSubmit({ name, gender })}>
        <div>
          <input
            onChange={onNameChange}
            value={name}
            type="text"
            name="name"
            placeholder="Friend's Name"
          />
        </div>
        <div>
          <select onChange={onGenderChange} name="gender" value={gender}>
            <option value="Male">Male</option>
            <option value="Female">Female</option>
            <option value="Other">Other</option>
          </select>
        </div>
        <div>
          <button type="submit">Add</button>
        </div>
      </form>
      <div className="boxes">
        {friends.map(({ name, gender }, index) => (
          <FriendBox key={`friend_${index}`} gender={gender}>
            <div className="box-name">Name: {name}</div>
            <div className="gender-container">
              <img src={gender === 'Female' ? female : male} alt="" />
            </div>
          </FriendBox>
        ))}
      </div>
    </div>
  )
}

export default App
```

The styles used for the boxes here are:

src/styles.css

```css
.boxes {
  margin: 10px 0;
  padding: 3px;
  display: grid;
  grid-gap: 10px;
  grid-template-columns: repeat(3, 1fr);
  grid-template-rows: 1fr;
}

.box {
  font-size: 18px;
  display: flex;
  justify-content: center;
  align-items: center;
  flex-direction: column;
  width: 100%;
  height: 100%;
  overflow: hidden;
}

.box-name {
  display: flex;
  align-items: center;
  height: 50px;
}

.box.gender-container {
  position: relative;
}

.box img {
  object-fit: cover;
  width: 100%;
  height: 100%;
}
```

Oh, bummer! One thing we forgot to do is bring in the _undo_ method so we can use it in the interface! Go ahead and destructure that out from _useApp_ and place it on the _Undo_ button:

src/App.js

```jsx
const App = () => {
  const { onSubmit, friends, undo } = useApp()

  const [name, setName] = useState('')
  const [gender, setGender] = useState('Male')
  const onNameChange = (e) => setName(e.target.value)
  const onGenderChange = (e) => setGender(e.target.value)

  const resetValues = () => {
    setName('')
    setGender('Male')
  }

  return (
    <div>
      <form className="form" onSubmit={onSubmit({ name, gender }, resetValues)}>
        <div>
          <input
            onChange={onNameChange}
            value={name}
            type="text"
            name="name"
            placeholder="Friend's Name"
          />
        </div>
        <div>
          <select onChange={onGenderChange} name="gender" value={gender}>
            <option value="Male">Male</option>
            <option value="Female">Female</option>
            <option value="Other">Other</option>
          </select>
        </div>
        <div>
          <button type="submit">Add</button>
        </div>
      </form>
      <div className="undo-actions">
        <div>
          <button type="button" onClick={undo}>
            Undo
          </button>
        </div>
      </div>
      <div className="boxes">
        {friends.map(({ name, gender }, index) => (
          <FriendBox key={`friend_${index}`} gender={gender}>
            <div className="box-name">Name: {name}</div>
            <div className="gender-container">
              <img src={gender === 'Female' ? female : male} alt="" />
            </div>
          </FriendBox>
        ))}
      </div>
    </div>
  )
}
```

Now when the user hits the _Undo_ button, their last action should be restored!

![2](https://jsmanifest.s3-us-west-1.amazonaws.com/posts/enhance-your-react-app-with-undo-reset-abilities/2.gif)

Everything's going perfectly as planned. The user is able to add their friends to the list, easily notice which ones are female and male in the interface, and undo their previous submissions.

...did you also notice that there's now a _resetValues_ method in the _App_ component, where it is being passed in to _onSubmit_ as the second argument? One thing that might feel a little bit odd for users is that their input isn't clearing after they submit a friend. Do they still need that same name there? Unless they have two or three friends with the same name, they're sure to hit their backspace button and clear it themselves. But we as developers have the ability to make their lives easier, so that's why we implemented a _resetValues_.

Having said that, it should be declared as the _second parameter_ to _onSubmit_ since we passed it in as the _second argument_ in the UI component:

src/useApp.js

```jsx
const useApp = () => {
  const [state, dispatch] = useReducer(reducer, initialState)

  const onSubmit = (friend, resetValues) => (e) => {
    e.preventDefault()
    if (!friend.name) return
    dispatch({ type: 'add-friend', friend })
    resetValues()
  }

  const undo = () => {
    dispatch({ type: 'undo' })
  }

  return {
    ...state,
    onSubmit,
    undo,
  }
}
```

Our undo feature should be working 100% fine by now, but i'm going to go a little further to make this a little more complex because an _undo_ can be compatible with just about anything.

Therefore, we're going to allow the user to declare a theme color for the interface so that they won't get too bored of white:

src/useApp.js

```jsx
const initialState = {
  friends: [],
  history: [],
  theme: 'light',
}
```

src/useApp.js

```jsx
const reducer = (state, action) => {
  switch (action.type) {
    case 'set-theme':
      return { ...state, theme: action.theme, history: insertToHistory(state) }
    case 'add-friend':
      return {
        ...state,
        friends: [...state.friends, action.friend],
        history: insertToHistory(state),
      }
    case 'undo': {
      const isEmpty = !state.history.length
      if (isEmpty) return state
      return { ...state.history[state.history.length - 1] }
    }
    case 'reset':
      return { ...initialState, history: insertToHistory(state) }
    default:
      return state
  }
}
```

Also, I declared an _insertToHistory_ utility to bring us extra benefits in case we passed in a weird value in the future for the state argument as you might have noticed above:

```jsx
const insertToHistory = (state) => {
  if (state && Array.isArray(state.history)) {
    // Do not mutate
    const newHistory = [...state.history]
    newHistory.push(state)
    return newHistory
  }
  console.warn(
    'WARNING! The state was attempting capture but something went wrong. Please check if the state is controlled correctly.',
  )
  return state.history || []
}
```

I'd like to add that it's a very important habit to think ahead as your app gets [larger and more complex](https://medium.com/better-programming/12-things-not-to-do-when-building-react-apps-with-redux-3a278705de93?source=---------7------------------).

Now continuing with the _theme implementation_, we'll define a custom method that the UI components can leverage:

src/useApp.js

```jsx
const onThemeChange = (e) => {
  dispatch({ type: 'set-theme', theme: e.target.value })
}

return {
  ...state,
  onSubmit,
  undo,
  onThemeChange,
}
```

Applying the theme components and the method to the interface:

src/App.js

```jsx
import React, { useState } from 'react'
import cx from 'classnames'
import female from './images/female.jpg'
import male from './images/male.jpg'
import useApp from './useApp'

const FriendBox = ({ gender, ...props }) => (
  <div
    className={cx('box', {
      'teal-border': gender === 'Male',
      'hotpink-border': gender === 'Female',
    })}
    {...props}
  />
)

const App = () => {
  const { onSubmit, friends, undo, theme, onThemeChange } = useApp()

  const [name, setName] = useState('')
  const [gender, setGender] = useState('Male')
  const onNameChange = (e) => setName(e.target.value)
  const onGenderChange = (e) => setGender(e.target.value)

  const resetValues = () => {
    setName('')
    setGender('Male')
  }

  return (
    <div>
      <div>
        <h3>What theme would you like to display?</h3>
        <div>
          <select onChange={onThemeChange} name="theme" value={theme}>
            <option value="light">Light</option>
            <option value="dark">Dark</option>
          </select>
        </div>
      </div>
      <div>
        <h3>Add a friend</h3>
        <form
          className="form"
          onSubmit={onSubmit({ name, gender }, resetValues)}
        >
          <div>
            <input
              onChange={onNameChange}
              value={name}
              type="text"
              name="name"
              placeholder="Friend's Name"
            />
          </div>
          <div>
            <select onChange={onGenderChange} name="gender" value={gender}>
              <option value="Male">Male</option>
              <option value="Female">Female</option>
              <option value="Other">Other</option>
            </select>
          </div>
          <div>
            <button type="submit">Add</button>
          </div>
        </form>
      </div>
      <div>
        <h3>Made a mistake?</h3>
        <div className="undo-actions">
          <div>
            <button type="button" onClick={undo}>
              Undo
            </button>
          </div>
        </div>
      </div>
      <div className="boxes">
        {friends.map(({ name, gender }, index) => (
          <FriendBox key={`friend_${index}`} gender={gender}>
            <div className="box-name">Name: {name}</div>
            <div className="gender-container">
              <img src={gender === 'Female' ? female : male} alt="" />
            </div>
          </FriendBox>
        ))}
      </div>
    </div>
  )
}

export default App
```

Since we added the _theme_ changing feature, it's probably a good idea to add in some conditional styles as well to accomodate the changes, right?

```jsx
 <div className={cx({
    'theme-light': theme === 'light',
    'theme-dark': theme === 'dark',
  })}
  // ...rest of the component
```

And here are the styles for that:

src/styles.css

```css
.theme-light,
.theme-dark {
  box-sizing: border-box;
  transition: all 0.15s ease-out;
  padding: 12px;
  min-height: 100vh;
}

.theme-light {
  color: #145269;
  background: #fff;
}

.theme-dark {
  color: #fff;
  background: #0b2935;
}
```

Awesome! Here is what our interface can do now!

![3](https://jsmanifest.s3-us-west-1.amazonaws.com/posts/enhance-your-react-app-with-undo-reset-abilities/3.gif)

Give yourselves a round of applause for making it this far!

Let's not celebrate yet though, because the title of this article also mentions a _reset_ feature for the interface.

Let's do that now by defining the switch case right on the reducer that we currently have:

src/useApp.js

```jsx
const reducer = (state, action) => {
  switch (action.type) {
    case 'set-theme':
      return { ...state, theme: action.theme, history: insertToHistory(state) }
    case 'add-friend':
      return {
        ...state,
        friends: [...state.friends, action.friend],
        history: insertToHistory(state),
      }
    case 'undo': {
      const isEmpty = !state.history.length
      if (isEmpty) return state
      return { ...state.history[state.history.length - 1] }
    }
    case 'reset':
      return { ...initialState, history: insertToHistory(state) }
    default:
      return state
  }
}
```

Now of course what that means next is having to define the method to signal that reducer for the state change. Don't forget to return it at the end of the hook!

src/useApp.js

```jsx
const reset = () => {
  dispatch({ type: 'reset' })
}

const onThemeChange = (e) => {
  dispatch({ type: 'set-theme', theme: e.target.value })
}

return {
  ...state,
  onSubmit,
  onThemeChange,
  undo,
  reset,
}
```

Destructuring it from the hook in the UI component:

src/App.js

```jsx
const { onSubmit, friends, undo, theme, onThemeChange, reset } = useApp()
```

src/App.js

```jsx
<div>
  <h3>Made a mistake?</h3>
  <div className="undo-actions">
    <div>
      <button type="button" onClick={undo}>
        Undo
      </button>
    </div>
    <div>
      <button type="button" onClick={reset}>
        Reset
      </button>
    </div>
  </div>
</div>
```

Last but not least, the styles used for those actions to align them horizontally:

src/styles.css

```css
.undo-actions {
  display: flex;
  align-items: center;
}

.undo-actions > div {
  margin: auto 3px;
}
```

Result:

![4](https://jsmanifest.s3-us-west-1.amazonaws.com/posts/enhance-your-react-app-with-undo-reset-abilities/4.gif)

Don't you just love how resetting the interface is also being captured by _undo_?

If you chose to download and clone the repository, you will see slight modifications as shown below:

src/App.js

```jsx
import React, { useState } from 'react'
import cx from 'classnames'
import useApp from './useApp'
import ThemeControl from './ThemeControl'
import AddFriend from './AddFriend'
import UndoResetControl from './UndoResetControl'
import Friends from './Friends'
import './styles.css'

const App = () => {
  const { friends, theme, onSubmit, onThemeChange, undo, reset } = useApp()

  const [name, setName] = useState('')
  const [gender, setGender] = useState('Male')
  const onNameChange = (e) => setName(e.target.value)
  const onGenderChange = (e) => setGender(e.target.value)

  const resetValues = () => {
    setName('')
    setGender('Male')
  }

  return (
    <div
      className={cx({
        'theme-light': theme === 'light',
        'theme-dark': theme === 'dark',
      })}
    >
      <ThemeControl theme={theme} onChange={onThemeChange} />
      <AddFriend
        onSubmit={onSubmit({ name, gender }, resetValues)}
        onNameChange={onNameChange}
        onGenderChange={onGenderChange}
        currentValues={{ name, gender }}
      />
      <UndoResetControl undo={undo} reset={reset} />
      <Friends friends={friends} />
    </div>
  )
}

export default App
```

It is the _same_ code except I organized it to be a little more readable and maintainable by separating the components to their own files.

## Bonus

Earlier in the beginning of the tutorial I mentioned an interface that you can display to users--giving them the option to choose which previous state of the app that they can revert back to if desired. Here is an example of that in use:

![bonus](https://jsmanifest.s3-us-west-1.amazonaws.com/posts/enhance-your-react-app-with-undo-reset-abilities/bonus.gif)

## Conclusion

Undoing things is very useful to us because we humans never stop making mistakes... let's face the truth. I hope that means you found this to be really useful to you :)

See you guys next time and you can follow me if you want to read more from me in the future!

Feel free to follow me on [medium](https://medium.com/@jsmanifest)!