April 13, 2019   • 5 min read

I wrote this post for my newsletter, sign up here to get emails like these every week.


What are hooks?

I am back with my new article and yep👍 it’s a technical one. It’s about React hooks. A new feature officially introduced in React v16.8.

If we have to understand it in a single simple definition we can say that hooks let us use state and other react features without writing class.

 

Whenever you need to make your module to behave differently or to react when some event happens, a term ‘hooks’ comes in action to make it possible.

 

For some weeks I have been playing with hooks and now I really like it.

You can find so many articles of react hooks if you search it out on google, and so many of you already aware or using it at some level of the development.

So, what’s the meaning of reading this article?

 

Reason

1. No longer need of reading long documentation.

2. It makes you remind very basic things of react hooks.

3. Simple and Basic examples of hooks with an explanation.

 

In this article I will cover useState and useEffect and useReducer hooks.

So, let’s start with a useState

useState

Previously, you had to convert your custom component into a class to use state inside it.

Now, you can add state to your custom component without making it as a class component using useState.

The useState hook lets you add a state to your existing functional component without converting it into a class.

Below is the simple functional component:

function Example() {
    return (
        <div />
    )
}

Before, you had to convert it as a class to add state in it like below:

class Example extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            ... state variables
        };
    }

    render() {
        return (
            <div />
        )
    }
}

Now, you can add state to your existing function component without converting it into class. You can do it by useState hook.

function Example() {
  const [count, setCount] = useState(0);
  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}

Here, count is your state and setCount is a method to set your count state. useState(0) assigns initial value as a 0 to count. So, useState takes a parameter which is an initial state for the declared state variable. Here initial state of the count is 0

 

useEffect

The Effect hook lets you perform side effects in function components

So, what are the side effects of functional components?

API calling, dynamic changing of DOM, subscription of events are examples of side effects.

Effect hook’s working is a combination of componentDidMount, componentDidUpdate and componentWillUnmount.

useEffect(
    // ---------- Function ------------
    () => {
        return function cleanUp() {  // function for cleanup registered side effects
            clean any registered side effect
        }
    }, 
    // ---------- Function ------------
    [variable] // Dependencies (optional)
)

useEffect takes two params one is function and other is dependencies.

A function is considered as a side-effect that calls based on dependencies.

 

No dependencies : Our function effect applies on every render like componentDidUpdate

[] : Effect applies only once, similar to componentDidMount

[variable] : Effect applies every time whenever variable value changes. So, no more comparison with prevState

cleanUp function : Effect hook’s first param can return a function which is used to clean any registered event to prevent memory leak from your component. You can say componentWillUnmount to this function.

 

function ExampleUseEffectWithAPI() {
    const [news, setNews] = useState({});
    const [country, setCountry] = useState('in');
    const [loading, setLoading] = useState(false);
    useEffect(() => {
        setLoading(true);
        fetch(`https://newsapi.org/v2/top-headlines?country=${country}&category=sports&apiKey=58a96540705c4234b0cbcc2357eda2b9`)
            .then(response => response.json()).then((newsData) => {
                setNews(newsData);
                setLoading(false);
            })
        return function cleanUp() {
            setNews({});
            setLoading(false);
        }
    }, [country])

    return (
        {
            loading 
                ? (<div>Loading news....</div>)
                : (
                    <div>
                        Total {news.totalResults} news found.
                        <button onClick={() => country == 'in' ? setCountry('us') : setCountry('in')}>
                            Set Country to {country == 'in' ? 'US' : 'IN'}
                        </button>
                    </div>
                )
        }
    )
}

Here, we had added 3 state news, country and loading with respective setter methods.

after that, we have added one side effect by calling news API inside the Effect hook. Other logic you can understand by just referring it.

Let me explain the key points. first is cleanUp function. Here, we had it in example, to let you know where you can write your code for cleanup so that when you leaving your component, at that time it doesn’t leads to any memory leak. i.e. setting interval leads to a memory leak if you don’t clear the interval on componentWillUnmount

Then you can see the country as the second param. So, whenever the country state changes, your given effect is going to apply. It does the work of your componentDidUpdate with the condition of checking the current state with the previous one.

componentDidUpdate = (prevState) => {
    if(prevState.country != this.state.country){
        ......your side effect
    }
}

 

useReducer

Reducer hooks used to handle complex state logic having multiple sub values or when current state depends on the previous one

If you know the concept of redux then you can easily understand how it works.

const initialState = { fruit: 'Banana' };

function reducer(state, action) {
    switch (action.type) {
        case 'changeFruit':
            return { fruit: action.fruit };
        default:
            throw new Error();
    }
}

function Shop() {
    const [state, dispatch] = useReducer(reducer, initialState);
    return (
        <>
            Count: {state.fruit}
            <button onClick={() => dispatch({ type: 'changeFruit', fruit:'Orange' })}>Update Fruit</button>
        </>
    );
}

Here, you can see that, I made Shop function component with the useReducer hook.

userReducer hook accepts three params reducer function, initial state values object and the last one is the function to initialize your state lazily so, you can reset those state by calling that function.

In the above example, we had updated fruit state using useReducer. Reducer hook return state object and dispatch method.

using state you can access all added state in reducer. dispatch works as same as it works in redux, you have to pass action object as a param so that different state updates accordingly.

 

Hope this is helpful 🙏 for someone

Nishith