An Introduction to React Hooks

By Amitai B.

Dec 28, 2018

React hooks are a new feature introduced in version 16.7.0-alpha.

They are not “revolutionary” because they do not amount to a clear break from the past; react will still be compatible with older code, but as this new feature matures, it will change the way we use react.

What are react hooks?

React hooks are a set of methods that can be used within react components. They add novel functionality like state management, component lifecycle, and more. Up until now, those capabilities were only available to class components and not functional ones. The motivation behind adding hooks is to make the code cleaner and clearer, more “functional” and improve performance, because functions are translated into a faster code than classes.

Personally, I prefer using as many function components as I can, and found class components less attractive, and so I’m very much in favor of react hooks.

There are many hooks available:

useState

useEffect

useContext

useReducer

useCallback

useMemo

useRef

useImperativeMethods

useLayoutEffect

In this post, I will delve into useState and useEffect hooks and how to use them.

useState

useState allows you to add a local state into a functional component. Just to be clear, this state is local to the component (like in a class component), and not global as in redux or mobx. There are highly technical ways to use it as a global state, but that takes us beyond the purpose of this post. It is important to keep in mind that functional components can have multiple independent states.

Here is an example of a simple component that counts the number of clicks:

import React, { useState } from "react";

export function App() {
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
    </div>
  );
}

useState establishes as a parameter the initial state and returns two objects:

It receives the newly created state object, and a method to change the state. Every time the method is called, the component is re-rendered with the new state.
In this example, the state is the count of clicks. Every time the user presses the button, setCount is called with the new count.

Very simple right?

As I said before, the component can have multiple independent states of a different type:

import React, { useState } from "react";

export function MultipleStates() {
  const [count, setCount] = useState(0);
  const [flag, setFlag] = useState(false);

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>Click me</button>
      <p>Flag is {flag.toString()}</p>
      <button onClick={() => setFlag(!flag)}>Change flag</button>
    </div>
  );
}

I added a new state for a flag, which changes from true to false.

useEffect

The useEffect hook is very similar to the componentDidMount lifecycle method in a class component.

You can use this hook to add functionality before or after the the function is called. You can control if the effect will run every time the function runs (the “render” of the component), only once or every time a value (usually a prop) has changed.

“` import React, { useEffect } from ‘react’;

export function LifecycleDemo() {
useEffect(() => {
console.log(‘render!’);
return () => console.log(‘unmounting…’);
})

return I’m a lifecycle demo;

useEffect gets as a parameter a function that will run when the function will be called (“render”). If it returns a method, the returned method will run when the component unmounts.

A great use case is available when fetching data from an API. In the next example, I will use both setState and setEffect to fetch and show data from an API:

import React, { useEffect, useState } from ‘react’;

export function FetchData() {
const [name, setName] = useState({ title: “”, first: “”, last: “”});

useEffect(async () => {
const res = await fetch(‘https://randomuser.me/api/’);
const json = await res.json();
setName(json.results[0].name);
},[])

return (
{The person name is: ${name.title} ${name.first} ${name.last}}
);
}

It is important to note the second parameter of useEffect. When I add an empty array, the useEffect will occur only once. Without it, it will be called every state change, which means it will run continuously. Why does this occur?

The last example will show how to fetch the call useEffect only when needed. I will add a wrap component that will change the gender of the person:

import React, { useEffect, useState } from “react”;

function FetchDataWithGender({ gender }) {
const [name, setName] = useState({ title: “”, first: “”, last: “” });

useEffect(
async () => {
const res = await fetch(https://randomuser.me/api?gender=${gender});
const json = await res.json();
setName(json.results[0].name);
},

[gender]

);

return (
{The person name is: ${name.title} ${name.first} ${name.last}}
);
}

export function WrapperFetchDataWithGender() {
const [gender, setGender] = useState(“female”);

return (

Select Gender setGender(“male”)}>Male setGender(“female”)}>Female
);
}
“`

Here, useEffect gets “gender” as the second parameter (in the array), and only if the gender is changed, it will re-fetch the data from the API.

Conclusion

As you can see in the previous examples, hooks are extremely useful and can make the code much more elegant. I encourage you to try them out, but advise you to wait until they are ready before using them in production.

Additionally, hooks also allow users to share code between components because you can use the same states or effects for different components. Many hooks are available online, and you can use them in your code. https://usehooks.com is an example of such a repository.

All code can be found here.

References

  • https://reactjs.org/docs/hooks-intro.html
  • https://daveceddia.com/

Leave a Reply

Your email address will not be published.