When React was first released, I ignored it. For a pretty long time, too. But customer demand eventually forced me to take another look at it and I started writing some web applications with it. Than even more and more.

However, it always felt a bit strange to me working with it. We had classical components and we had functional components. The latter were supposed to be faster and clearer than the former, but: no state. And in the end, internally React would turn them into classical components anyways.

The situation was so confused that I even advised agains using functional components. I was working with a client that had lots of developers who were not especially fit in Javascript and grasping the difference between the two ways of writing components was very difficult for them. In the end we had to re-write lots of components because they turned out to require state or needed to tap into the component lifecycle somehow that it was a complete mess. The better solution was to completely go with component classes because everyone was crystal clear about how to implement components this way.

When hooks were introduced, I was blown away. The syntax was so easy and clear to understand that I truly asked myself why nobody had thought about that solution in all those years before since functional components existed. I tried the React 16.7 alpha which turned out to be pretty stable. I decided to take a risk and implement a customer project based on that alpha version and I was not disappointed. I hardly encountered any bugs, I have 100% functional components in my project and I was able to upgrade React to the current 16.8.1 without any problems.

For me, application development with React improved through hooks tremendously. The only improvement in my development lifetime that I experience as great as this is when I started using  requireJS (does anyone remember it).

Using State

This is pretty straightforward:

import React from 'react';

const MyComponent = () => {
    const [count, setCount] = React.useState(0);
    
    const addOne = () => setCount(count + 1);
    
    return <Button onClick={addOne}>You clicked me {count} times!</Button>
}

In my opinion, this is easy to understand. I already mixed in my personal flavor of using the native React hooks: I don't import them separately. Often, you see examples like this:

import React, {useState} from 'react';

const MyComponent = () => {
    const [myVal, setMyVal] = useState(null);
    // ...
}

Most of the times, useState will be imported separately, just so you can omit the React. in front of it. I prefer not importing the hook separately but using it directly from the React object. This spares you the hassle to modify your import statement in case you decide to now use a React native hook.

Its recommended that you call useState()for every state value that you need. But you may also store complete objects there, safely. Just remember that you make a copy of the object before you modify it and then send the copy to the setter function.

What about Life Cycle Methods?

The hooks update reduces the lifecycle to basically two things: componentDidMount and componentWillUnmount. The way of writing this is still a bit... well:

import React from 'react';

const MyComponent = () => {
    React.useEffect(() => {
        console.log('I have been mounted!');
        
        return () => {
            console.log('I have been unmounted');
        };
    });
};

So it works like this: you call React.useEffect()inside your component and pass a callback function to it. This function will be called, when the component did mount. If you want to do something when the component will unmount, your first callback needs to return a second callback. That second callback is eventually called before unmount. Phew. I don't really like this pattern, but well - you will get used to it.

Custom Hooks

This is where the real strength of the react hooks lie. Hooks are just functions. You can create your own! I use this heavily and abstracted away the usage of redux from my projects:

import React from 'react';
import {useArticle} from './customHooks';
import LoadGuard from './LoadGuard';

const ArticleDisplay = ({id}) => {
    const [article, articleStatus] = useArticle(id);
    
    return (
        <LoadGuard status={articleStatus}>
            {() => (
                <div>
                    <h1>{article.headline}</h1>
                    {article.body.map(paragraph => <p>{paragraph}</p>)}
                </div>
            )}
        </LoadGuard>
    );
};

This works incredibly well for me: the hook eventually returns an article object. Since its requested over the network the first time I request it, it might not be available initially. Thats where the LoadGuard component comes into play: it checks the loading status of the article and will render a loading placeholder until the status changes to done - then the article will be rendered.

For data editing purposes, the article hook offers even more things:

const [article, articleStatus, saveArticle, deleteArticle] = useArticle(id);

So you receive update and delete handlers that you can call right from your component. The hook takes care of everything. Oh and if you don't pass an id, a new, blank article object will be returned that can be edited and saved.

I will write more about this concept and how to write data hooks like that in a separate article.