Hooked on React hooks
Tags: react, javascript, webdev
Published: 2019-03-17 17:36:08

---
title: Hooked on React hooks
published: true
description: Using state and lifecycle functions in React without a class component is impossible! Not anymore. React hooks provide a functional way to access React features without the need of class components.
tags: react, javascript, webdev
---

Whenever I read about a new feature in React, I'm all over it. I try to understand what's going on and how I could apply this new feature to my projects.

<code>Hooks</code> is one of the newest features of React. It was introduced in React 16.8 and it allows you to use state and lifecycle features in components which are not a class.

To use React Hooks you need to update React to version 16.8 or higher. Don't forget to also update <code>react-dom</code> and, if you use it, <code>react-hot-loader</code>. You will run into some strange errors if you don't update the hot loader.

##The state hooks

As you may know in the pre 16.8 days, if you wanted to use state you needed to do something like this:

```javascript

import React, {Component} from 'react';

class Something extends Component {

    constructor(props){
        super(props);

        this.state = {
            foo: 'bar'
        }

        this.setFoo = this.setFoo.bind(this);
    }

    setFoo(newFoo) {
        this.setState({...this.state, foo: newFoo});
    }

    render() {
        const {foo} = this.props;

        return (
            <div>
                <span>{foo}</span>
                <button onClick={this.setFoo('theRealFoo')}>Set Foo</button>
            </div>
        );
    }

}

export default Something;

```
This example contains much code that is necessary to make the class in JavaScript work. To use <code>this</code> in the right context, you need to give the function some special attention. The same example would look like this with hooks:

```javascript

import React, {useState} from 'react';

const Something = () => {

    const [foo, setFoo] = useState("bar");

    return (
        <div>
            <span>{foo}</span>
            <button onClick={setFoo('theRealFoo')}>Set Foo</button>
        </div>
    );
}

export default Something;

```

As you can see, the amount of code is significantly less. In this case <code>useState</code> is a hook provided by React. It is a function which returns a state value and a function which is used to update it. 

So there is no need for <code>setState</code> anymore. React takes care of everything. 

<code>useState</code> takes a parameter which is the initial value for the state field. 

Now sometimes state can become complex and you might need more than one variable for it. To manage this, you can use multiple <code>useState</code> calls to create multiple state variables or you can use an object like you did with classes before.

I tried both ways and I think single variables are much easier to handle, because you don't need to do all the nested object merging as you might have done before.

Also React has another hook called <code>userReducer</code>, which comes in handy when you have complex state handling. As in Redux, you use a function which takes the state and an action to update the state.

```javascript

import React, {useReducer} from 'react';

const csReducer = (state, action) => {
    switch(action.type) {
        case 'foo': {
            return 'foo';
        }
        case 'bar': {
            return 'bar';
        }
        default: {
            return state;
        }
    }
}

const ComplexSomething = (props) => {
    const [someState, dispatch] = useReducer(csReducer, props.someState);

    return (
        <div>
            <span>{someState}</span>
            <button onClick={dispatch({type: 'foo'})}>Say Foo!</button>
            <button onClick={dispatch({type: 'bar'})}>Say Bar!</button>
        </div>
    )
} 

export default ComplexSomething;

```
You can see that the whole state handling is in the <code>csReducer</code>. It takes the action and depending on the type, it returns another value for the state. You can also send a payload <code>{type: 'someAction', payload: 'foobar!'}</code> to put maybe a fetched information into the state. If you return the state as it was given, React does not change the state and no rerenders are triggered.

As you can see, the state handling is pretty awesome. Either you do some easy stuff with <code>useState</code> or you start to raise the stakes with <code>useReducer</code>.

##Lifecycle with hooks 

Now that we can handle our state, you probably remember that I also mentioned you could do the lifecycle stuff with hooks. Let's talk about this.

There is a hook called <code>useEffect</code>. It is called like this, because most things you do in the lifecycle methods, fetching data, adding events to the DOM or something like that, all this is called "side effects", hence <code>useEffect</code>.

Let's have an example:

```javascript

import React, {useState, useEffect} from 'react';
import Spinner from './Spinner';

const EffectComponent = (props) => {

    const [pending, setPending] = useState(true);
    const [product, setProduct] = useState({});

    useEffect(() => {
        setPending(true);
        fetch(`https://myapi.api/product/${props.id}`).then((productData) => {
            setProduct(productData);

            setPending(false);
        })
    }, [props.id]);

    if(pending === true) return <Spinner />

    return (
        <div>{product.name}</div>
    )

}

export default EffectComponent;

```
At first we define our two state variables <code>pending</code> and <code>product</code>. Then we use <code>useEffect</code> to fetch data. The function sets <code>pending</code> to true and then loads data from an API. After the data arrived, it sets our <code>product</code> state and then <code>pending</code> to false, so our component will render.

The <code>effect</code> is called every single time the component renders. If you have used <code>componentDidMount</code> and <code>componentWillUpdate</code> before you know that it is a pain to manage when data should load and when not. With <code>useEffect</code> there is an easy solution to that. The second parameter is an array with variables. The <code>effect</code> will only fire if the variables in the array have changed. In the above example I do <code>[props.id]</code>, so the <code>effect</code> will only fire every time <code>props.id</code> changes. 

You can also return a function in <code>useEffect</code> which will be called when the component is unmounted. You can do some cleanup stuff there.

##A new way to share stateful logic

In the last versions of React there were two ways to share stateful logic between components. Render props and higher order components. Both are fine and they work well, but getting the concept... Phuuu... I tried to explain both a hundred times to different people and maybe 50% got it.

When using React 16.8 you can use hooks to share stateful logic between components. This way is much simpler, because a hook is just a function... and everyone understands functions, right?

To share the logic, we can build our own custom hooks and call them, just like we call the prebuilt hooks.

```javascript

import React, {useState} from 'react';

// This is the custom hook
function useFetchData(url, setData) {
    const [pending, setPending] = useState(true);
    const [error, setError] = useState(null);

    useEffect(() => {
        setPending(true);
        fetch(url).then((productData) => {
            setData(productData);

            setPending(false);
        }).catch(error =>{
            setError(error);
        })
    }, [url]);

    return {pending, error};
}

const EffectComponent = (props) => {
    const [product, setProduct] = useState({});

    // and here we call it.
    const {pending, error} = useFetchData(`https://myapi.api/product/${props.id}`, setProduct);

    if(pending === true) return <Spinner />

    return (
        <div>
            <span>{product.name}</span>
            {error && <span class="error">{error}</span>}
        </div>
    )

}

export default EffectComponent;

```
Look at the example above. What I did there is take away the logic for fetching data and put it into a function, this function is the custom hook. The convention is to start every hook with <code>use</code> and then your function name. Instead of rewriting the fetch logic, I now can simply use my <code>useFetchData</code> hook.

I think this concept is much easier to grasp. You just put everything in a function, you call it <code>hook</code>and you are done with it.

##The rules of hooks

Now hooks have some specific things you need to know before you use them. The React people call them "Rules of Hooks".

In fact, there are only two:

1.) You can use hooks only in function components

There is one exception to this rule. You can use hooks in your custom hooks.

2.) You can't use hooks in any kind of loop, nested functions or within conditions.

The last one is because React remembers in which order you used the hooks and it uses this order to give you the correct data or do the correct stuff.

For example:

```javascript

const [varA, setVarA] = useState(1);
const [varB, setVarB] = useState(2);
const [varC, setVarC] = useState(3);


```

This works fine. Whenever the component is called, the order of the hooks is the same. Whenever you use <code>varC</code>, it is the value 3.

```javascript

const [varA, setVarA] = useState(1);
if(varA === 2) {
    const [varB, setVarB] = useState(2);
}
const [varC, setVarC] = useState(3);


```
This one is a problem. The moment <code>varA</code> is 2, the order of the hooks changes and therefore things will go wrong.

##There are others

Yes, there are others... in fact, there are a whole bunch of other React Hooks. But I think they are more edge case hooks you probably don't need that often, if ever. <code>useMemo</code> could come in handy, if you want to do some heavy lifting within a function in the render process of your component. It takes a function and an array of values. The function only runs if the values in the array change. Otherwise it will return the memoized value. [You can read up on memoization here.](https://en.wikipedia.org/wiki/Memoization)

One hook looks really interesting, though. <code>useContext</code> I have to do some more testing with this one, but I think it will make use of Reacts' Context API much easier than it is right now.

Well, that's it for this post. I hope you learned something, I hope you enjoyed it at least a little bit. If you got tips or comments, feel free to post them.

Thank you for reading!