Practical React & Redux - Part 2
Tags: react, redux
Published: 2020-12-08 13:24:08

_Originally published at [Codegram's blog](https://www.codegram.com/blog/practical-react-and-redux-part-2)_

This is the second part of the React workshop series created by our team. Let's learn about how to create stateful components using React hooks.

It's been a while but finally awe have released the second part of our React workshop. Remember that you can download the code from the first part in [here](https://github.com/codegram/practical-react-and-redux). If you want to follow along just checkout the `part-1` tag and update the code as you read.

## Introduction

In the first part we created our first components using React, but we ended the workshop in a bit of a cliffhanger and encountered a bug 🐛. Today we are going to continue our application and start writing some stateful components.

## Stateful components with React hooks

We have created a bunch of stateless components or usually also called "dumb components". Starting now we are going to learn how to add some state to them. First we need to learn what is a React `hook`!

### useWhat? First overview of hooks

A hook is just a function, period. We can write our hooks and the convention is that they start with the prefix `use`. The hooks can only be executed inside components (or other hooks) so usually the hook just return something that can be used by the component.

A common use of hooks is to reuse some business logic. First let's create a `Cat` 😸 component (you need to create the corresponding folder structure as we did before):

```jsx
// src/cats/components/cat/Cat.js
import React from 'react'
import PropTypes from 'prop-types'

const Cat = ({ name, score }) => {
  const onClick = () => {
    score += 1
    console.log(`This is your new score: ${score}`)
  }

  return (
    <div>
      <p>{name}</p>
      <p>Score: {score}/10</p>
      <button onClick={onClick}>Increase score</button>
    </div>
  )
}

Cat.propTypes = {
  name: PropTypes.string.isRequired,
  score: PropTypes.number.isRequired,
}

export default Cat
```

Then, use the `Cat` component in our application to add a new cat to the view (😸 are also awesome so give them a good score!):

```jsx
// src/App.js
import React from 'react'
import Dog from './dogs/components/dog/Dog'
import Cat from './cats/components/cat/Cat'

const App = () => {
  return (
    <>
      <Dog name="Boira" score={13} />
      <Dog name="Black" score={13} />
      <Cat name="Uhura" score={13} />
    </>
  )
}

export default App
```

Nothing really fancy here! Now we have two components that are mostly identical. Let's fix this!. Let's create a `pets` module with a hooks folder, and we are going to create our first hook. We are going to copy the `onClick` function from the `Dog` component and use it inside our hook.

```jsx
// src/pets/hooks/useScore.js
const useScore = (score) => {
  return {
    increaseScore: () => {
      score += 1
      console.log(`This is your new score: ${score}`)
    },
  }
}

export default useScore
```

Notice that the hook is just a function that receives some value, `score` in this case, and returns a new object. I added the `increaseScore` function to the object so now we can use it inside our components.

Let's use it in the `Dog` component:

```jsx
// src/dogs/components/dog/Dog.js
import React from 'react'
import PropTypes from 'prop-types'

import useScore from '../../../pets/hooks/useScore'

const Dog = ({ name, score }) => {
  const { increaseScore } = useScore(score)

  return (
    <div>
      <p>{name}</p>
      <p>Score: {score}/10</p>
      <button onClick={increaseScore}>Increase score</button>
    </div>
  )
}

Dog.propTypes = {
  name: PropTypes.string.isRequired,
  score: PropTypes.number.isRequired,
}

export default Dog
```

Do the same for the Cat component, and we are done here! We have moved some common logic to a hook so now we can focus on fixing our problem. We need to make our view aware of that change in the score or, in other words, make the component stateful!

### Stateful components using useState

React already includes some hooks. We are going to use `useState` to add some `state` to our components. The difference between a prop and the state is that we can change the state to re-render our component when something changes!

Remember that we can use hooks inside other hooks so let's use the `useState` hook inside our custom hook `useScore` like this:

```jsx
// src/pets/hooks/useScore.js
import { useState } from 'react'

const useScore = (baseScore) => {
  const [score, setScore] = useState(baseScore)

  return {
    score,
    increaseScore: () => {
      setScore(score + 1)
      console.log(`This is your new score: ${score}`)
    },
  }
}

export default useScore
```

Hold up! There is a lot to digest in the previous snippet so let's review it step by step. First, we rename the hook argument to `baseScore` and passed it to the `useState` method, this is the initial value of our state. The `useState` function returns an array where the first element is our state and the second element is a function to replace our state. I used the word "replace" intentionally because we need to provide a new object always, otherwise it will not be updated (embrace the `immutability`!).

Then I added the `score` to the object that our custom hook is returning, so we have access to it in our component. Finally, I used the `setScore` function to set a new state when the `increaseScore` function is called. Neat, right?

Let's see how to use it in our components. I am gonna change the `Dog` component, and I am gonna leave the `Cat` component for yourselves as an excercise:

```jsx
// src/dogs/components/dog/Dog.js
import React from "react";
import PropTypes from "prop-types";

import useScore from "../../../pets/hooks/useScore";

const Dog = ({ name, initialScore }) => {
  const { score, increaseScore } = useScore(initialScore);

  return (
    <div>
      <p>{name}</p>
      <p>Score: {score}/10</p>
      <button onClick={increaseScore}>Increase score</button>
    </div>
  );
};

Dog.propTypes = {
  name: PropTypes.string.isRequired,
  **initialScore: PropTypes.number.isRequired,**
};

export default Dog;
```

I also changed the `Dog`'s `score` prop to `initialScore`so we need to update our application as well:

```jsx
// src/App.js
import React from 'react'
import Dog from './dogs/components/dog/Dog'
import Cat from './cats/components/cat/Cat'

const App = () => {
  return (
    <>
      <Dog name="Boira" initialScore={13} />
      <Dog name="Black" initialScore={13} />
      <Cat name="Uhura" initialScore={13} />
    </>
  )
}

export default App
```

After making all the changes you can refresh your browser and test your application. The view is also updated when we press the button! 🎉

React includes a small list of hooks: [https://reactjs.org/docs/hooks-reference.html](https://reactjs.org/docs/hooks-reference.html) but creating your own is straightforward.

## Conclusion

In this article we learned about how to add state to our a React application and written our first React hooks. Our application is basic but for a bigger application is better to rely on a state management library and that's the topic for our next article!.

You can find the code examples in this [repository](https://github.com/codegram/practical-react-and-redux). I also tagged the progress for [part 2](https://github.com/codegram/practical-react-and-redux/tree/part-2) in case you want to check the repository at this specific moment.

_Cover photo by [Henar Langa](https://unsplash.com/@henarlanga?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)_