React Hooks: A big change is coming

The new React Hooks API has just been published and can be the biggest change in React since the appearance of Jsx, taking an important turn in the way of working with React, with a much more functional orientation, and which can also mean the disappearance of classes and life cycles.

A great change is coming. Surely many remember when the ” functional ” or “stateless” components were introduced and there was the possibility of writing components using simple functions instead of classes, with its constructor, its binds, etc. It was a success and I think that in general, the whole community has assumed that it is always more comfortable, simple, elegant and easy to understand a simple function than a class, except in the case that you need to persist the state (hence they will be called staless) or manage life-cycle events, since these are only available in class components.

GOODBYE CLASSES?

Classes, and by extension object orientation is not a precisely new paradigm, since it dates back to the middle of the last century and the first language to apply it was Simula over there by 1967. Object-oriented programming is not precisely the paradigm of Efficiency, rather the opposite, object orientation has a high computational cost compared to other paradigms. While object orientation has always been seen as a mechanism of “sorting” the code, the reality is that it is often common to see huge classes, with gigantic methods and hundreds of getters & setters … Apart, in JavaScript, we have the problem of this , which forces us to have to use bind to not lose the context of this.

When React class components have some complexity, they usually have a large number of lines of code and become difficult to follow because, in addition, life cycle methods also do not help. All this makes it very difficult to reuse logic between components and hooks , they come to change precisely all this, because with the hooks all our components can be functional components, that is, a simple function, without giving up having no alternative state or forms that allow us to manage the life cycle of the components.

WHAT ARE HOOKS?

The hooks are a collection of different functions, each with a very clear and descriptive purpose and that are intended to be used within functional components, allowing us not only to have a state management or life cycle control between our functional components if not that in addition, it will allow us to reuse logic between our components and even create our own hooks. Throughout the post we will see examples of use of the main hooks and the code with the examples you can find in github .

The hooks follow a naming convention that uses use followed by a descriptor for the hook, so all hooks are useHookName, such as useState, which is probably the most important hook.

USESTATE

useState is the equivalent of the traditional state and will allow us to access the values ​​of the state, define a default state and also modify it, except that for this we will not have the traditional setState method since each state variable that we define (count ) will have its own modification function (setCount) as we see in the following example:

import React, { useState } from 'react';

const UseStateComponent = () => {
  //se define la variable count y su setter setCount utilizando destructuracion de Arrays
  const [count, setCount] = useState(0);// 0 es el valor inicial del state

  return (
     <div>
       Count: { count }
       <button onClick={() => setCount(count + 1)}>+</button>
       <button onClick={() => setCount(count - 1)}>-</button>
       <button onClick={() => setCount(0)}>Reset</button>
     </div>
  );
}

export default UseStateComponent;

Probably at first glance, the way in which state variables are defined is confusing and this is because the hooks make intensive use of Arrays destructuring and if you are not used to it, at first it costs a little . We can define as many properties as we want (as we will see in other examples) by calling useState for each of the variables or we can define an object, but in general it is better to use independent variables.

USEEFFECT

useEfect is a hook that is designed to execute side effects and that are essentially operations that happen outside the render. useEffect is the right place to make calls to services, raise listener events, etc. so it becomes the substitute for componentDidMount and componentDidUpdate since useEffect runs after the render itself.

import React, { useState, useEffect } from "react";

const UseEffectComponent = () => {
  //usamos useState para definir mouseEvent y su setter
  let [mouseEvent, setMouseEvent] = useState(0);
  
  useEffect(() => {
    //useEffect se ejecutará después del render y en él establecemos el listener
    document.addEventListener("mousemove", setMouseEvent, false); 
  });

  return (
   <fieldset>
      <div>
        X: { mouseEvent.clientX } 
        Y: { mouseEvent.clientX } 
      </div>
    </fieldset>
  );
}

export default UseEffectComponent;

The operation of the effects can be confusing at the beginning since it is important to keep in mind that they will be executed after each render, and if the effect is derived from a new render, the effect will be re-executed and so on until infinite. To avoid these situations, the effects have a mechanism to ensure that it is only executed once.

Let’s explain it a little better with a real world example. Let us think that we have an empty array of data and we want to fill it with a list of elements that comes from a call to a service, such as a list of posts, but logically we only want to make that call to the service only once using useEffect. To do this, we will tell useEffect that the initial value is an empty array, which we will fill with the posts, and useEffect will check if the value has changed so as not to run again:

import React, { useState, useEffect } from "react";

const UseEffectApiRequest = () => {
  //Definimos el array de posts
  let [posts, setPosts] = useState([]);
  //Queremos mostrar un loading mientras carga
  let [isLoading, setIsLoading] = useState(false);

  useEffect(() => {
    setIsLoading(true);//mostramos loading
    fetch('https://pablomagaz.com/api/posts')
      .then(response => response.json())
      .then(data => setPosts(data.posts))
      .finally(() => setIsLoading(false));//ocultamos el loading
  }, []); //El array vacío es el estado inicial y el effect no se volverá a ejecutar cuando su contenido cambie

  const loading = (isLoading) ? Loading... : null;

  return (
   <fieldset>
      <div>
        { loading  }
        { posts.map((post, key) => (
          <div key={ key }>
            { post.title }
          </div>
        ))}
      </div>
    </fieldset>
  );
}

export default UseEffectApiRequest;

USEREDUCER

Yes, indeed, you read correctly. useReducer is probably one of the most amazing hooks and a clear nod to Redux since it offers us the possibility of having Redux in a single hook and for this useReducer has a state and dispatch, in addition to needing a traditional Redux reducer, that is, a reduction function that returns the following state:

import React, { useReducer } from 'react';

// definimos un valor inicial para el store
const initialState = { count: 0 }; 

//definimos un reducer que recibirá el state y el action
const reducer = (state, action) => {
  switch (action.type) {
    case 'increment': return { count: state.count + 1 };
    case 'decrement': return { count: state.count - 1 };
    case 'reset': return initialState
    default: return state;
  }
}

const UseReducerComponent = () => {
  //state es el valor del store, y dispatch nos permite disparar acciones
  const [state, dispatch] = useReducer(reducer, initialState);// Nuestro reducer y el valor inicial

  return (
    <div>
      Count: { state.count }
      <button onClick={() => dispatch({ type: 'increment' })}>+</button>
      <button onClick={() => dispatch({ type: 'decrement' })}>-</button>
      <button onClick={() => dispatch({ type: 'reset' })}>Reset</button>
    </div>
  );
}

export default UseReducerComponent;

As we see in the example, useReducer takes care that every time we dispatch an action, the reduction we have defined will receive both the initial state, passed through useReducer, and the triggered action. Redux in a hook. Logically this opens a new debate about the future of Redux especially when we combine it with the Context Api and its hook version, useContext.

USECONTEXT

useContext is the hook in charge of managing the Context Api and of which we have already talked about in this post so I recommend you to give a review to understand well what this hook does, but basically api context allows us to create a mechanism (provider) to the passing of contexts in a hierarchy of components:

import React, { useContext, useState } from 'react';

const UseContextComponent = () => {
  //Create context devuelve { Provider, Consumer }
  const CountContext = React.createContext(15);
  const count = useContext(CountContext);

  return (
    <div>
      <CountContext.Provider value={ count }>
        { count }
      </CountContext.Provider>
    </div>
  );
}

export default UseContextComponent;

USECALLBACK

Optimization has been another focus with the new hooks. useCallback is the hook that allows memorization and prevents a function from being re-executed if its parameters have not changed, returning the stored or stored value. This is especially useful for operations that have a high computational cost or we want to control whether a component is re-rendered or not, as we do so far with shouldComponentUpdate, according to the parameters received by the function that returns it:

import React, { useState, useCallback } from 'react';

const UseCallbackComponent = () => {
  const [text, setText] = useState('Hello!');

  // Función que va a ser memorizada
  const ChildComponent = ({ text }) => {
    console.log('rendered again!');
    return (
      <div>
        { text }
      </div>
     );
  }

   // Gracias a useCallback solo se renderiza cuando el valor indicado (text) cambie
   const MemoizedComponent = useCallback(, [text]);

   return (
     <div>
       <button onClick={() => setText('Hello!')}>Hello!</button>
       <button onClick={() => setText('Hola!')}>Hola!</button>
       { MemoizedComponent }
     </div>
   );
}

export default UseCallbackComponent;

USEMEMO

useMemo is a variant of useCallback and also as an alternative to shouldComponentUpdate. The only real difference is the syntax since its operation is the same:

import React, { useState, useCallback, useMemo } from 'react';

//useCallback
const MemoizedComponent = useCallback(, [text]);

//useMemo
const MemoizedComponent = useMemo(() => , [text]);

USEREF

useRef is the hook for DOM references but we can see useRef also as a mechanism to define instance variables or even to allow us to access the previous props or state:

import React, { useRef, useState, useEffect } from 'react';

const UseRefComponent = () => {
  const [count, setCount] = useState(0);// 0 es el valor inicial

  // useRef se puede usar para alojar DOMS refs o cualquier tipo de referencia
  const prevCountRef = useRef();
  // Usamos useEffect para cambiar el valor de la referencia
  useEffect(() => {
    prevCountRef.current = count;
  });

  const prevCount = prevCountRef.current;

  return (
    <div>
      Count: { count } | Previous Count: { prevCount }
      <button onClick={() => setCount(count + 1)}>+</button>
      <button onClick={() => setCount(count - 1)}>-</button>
      <button onClick={() => setCount(0)}>Reset</button>
    </div>
  );
}

export default UseRefComponent;

We have seen the main hooks, although there are some more like useLayoutEffect , which is the synchronous version of useEffect or also useDebugValue that is a hook for debugging with React DevTools, however, it is always possible to create our own hooks, something that we will see in next posts 🙂

CONCLUSIONS

It is quite clear that hooks are going to mean a radical change in the way you work with React. The change is deep, very deep and can be difficult to adapt, especially at the beginning, since the derailment of Arrays can generate some “visual resistance”, but it is important to note that hooks do not imply that classes or life cycles are going to disappear since there will be no breaking changes and compatibility with the usual classes will be maintained so if you feel more comfortable with the class components you will be able to continue using them, at least for a while …

With the hooks, React turns to a much more functional and reactive model, which I am glad about the truth, and I think that in a fairly short space of time, the hooks will begin to be the basis of all the new developments with React.

As always, you can find all the examples of this post on github.

Leave a comment

Create your own website, free on WordPress.com.Create your own website.
Start free