En este artículo, crearemos una aplicación en React utilizando componentes de clase. Luego, lo convertiremos en componentes funcionales usando React Hooks paso a paso.

Al crear esta aplicación, aprenderás:

  • Cómo hacer llamadas a una API
  • Cómo implementar funcionalidad de cargar más
  • Cómo depurar problemas de la aplicación
  • Cómo usar async/await
  • Cómo actualizar el componente cuando algo cambia
  • Cómo solucionar el problema del bucle infinito en el hook useEffect
  • Cómo refactorizar componentes basados ​​en clases en componentes funcionales con Hooks

y mucho más.

Entonces empecemos.

Configuración inicial del proyecto

Crea un nuevo proyecto usando create-react-app:

npx create-react-app class-to-hooks-refactoring

Una vez tu proyecto este creado, elimina todos los archivos de la carpeta src y crea el archivo index.js y el archivo styles.css dentro de la carpeta src. También, crea una carpeta components dentro de la carpeta src.

Instala la librería axios ejecutando el siguiente comando desde la carpeta de tu proyecto:

yarn add axios@0.21.1

Abre el archivo styles.css y agrega el contenido desde este repositorio de GitHub.

Cómo crear las páginas iniciales

Crea un nuevo archivo llamado Header.js dentro de la carpeta components con el siguiente contenido:

import React from "react";

const Header = () => {
  return <h1 className="header">Random Users</h1>;
};

export default Header;

Crea un nuevo archivo llamado App.js dentro de la carpeta src con el siguiente contenido:

import React from 'react';
import Header from './components/Header';

export default class App extends React.Component {
  render() {
    return (
      <div className="main-section">
        <Header />
        <h2>App Component</h2>
      </div>
    );
  }
}

Ahora, abre el archivo index.js y agrega el siguiente contenido en él:

import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './styles.css';

ReactDOM.render(<App />, document.getElementById('root'));

Ahora, inicia la aplicación ejecutando el comando yarn start desde la terminal.

Podrás ver la siguiente pantalla sí accedes a la aplicación en http://localhost:3000/.

index_page

Cómo hacer llamadas a una API

Usaremos la API de Random Users para obtener una lista de usuarios aleatorios.

Así que abre tu archivo App.js y agrega el método componentDidMount dentro del componente:

componentDidMount() {
    axios
      .get('https://randomuser.me/api/?page=0&results=10')
      .then((response) => {
        console.log(response.data);
      })
      .catch((error) => console.log('error', error));
  }

También, importa axios en la parte superior del archivo:

import axios from 'axios';

Todo su archivo App.js se verá así ahora:

import React from 'react';
import Header from './components/Header';
import axios from 'axios';

export default class App extends React.Component {
  componentDidMount() {
    axios
      .get('https://randomuser.me/api/?page=0&results=10')
      .then((response) => {
        console.log(response.data);
      })
      .catch((error) => console.log('error', error));
  }

  render() {
    return (
      <div className="main-section">
        <Header />
        <h2>App Component</h2>
      </div>
    );
  }
}

Aquí, estamos haciendo una llamada al API para obtener inicialmente una lista de 10 registros en la URL https://randomuser.me/api/?page=0&results=10.

Ahora, si verificas la aplicación, verás la respuesta del API en la consola.

result-1

Ahora, declaremos un estado para almacenar el resultado y los indicadores relacionados con la carga y los mensajes de error.

Reemplaza el contenido de App.js con el siguiente código:

import React from 'react';
import Header from './components/Header';
import axios from 'axios';

export default class App extends React.Component {
  state = {
    users: [],
    isLoading: false,
    errorMsg: ''
  };

  componentDidMount() {
    this.setState({ isLoading: true });
    axios
      .get('https://randomuser.me/api/?page=0&results=10')
      .then((response) => {
         this.setState({ users: response.data.results, errorMsg: '' });
      })
      .catch((error) =>
        this.setState({
          errorMsg: 'Error while loading data. Try again later.'
        })
      )
      .finally(() => {
        this.setState({ isLoading: false });
      });
  }

  render() {
    const { users, isLoading, errorMsg } = this.state;
    console.log(users);

    return (
      <div className="main-section">
        <Header />
        {isLoading && <p className="loading">Loading...</p>}
        {errorMsg && <p className="errorMsg">{errorMsg}</p>}
      </div>
    );
  }
}

Aquí, hemos declarado un estado directamente dentro de la clase usando la sintaxis de propiedades de la clase, que es una forma común de escribir el estado en componentes basados ​​en clases.

state = {
  users: [],
  isLoading: false,
  errorMsg: ''
};

Luego, dentro del método componentDidMount primero establecemos el estado isLoading en true antes de realizar la llamada a la API.

this.setState({ isLoading: true });

Una vez que obtenemos la respuesta del API, almacenamos el resultado en la matriz de users que se declara en el estado. También estamos configurando el estado de errorMsg en vacío, de modo que si hay algún error anterior, se borrará.

this.setState({ users: response.data.results, errorMsg: '' });

Y en el bloque .catch, estamos configurando el errorMsg en caso de que haya algún error al realizar una llamada a la API.

Luego, usamos el bloque .finally para establecer el estado isLoading en false.

.finally(() => {
  this.setState({ isLoading: false });
});

Usar finally nos ayuda a evitar la duplicación de código aquí porque no necesitamos establecer isLoading a false en .then y en el bloque .catch nuevamente. Esto se debe a que el bloque finally se ejecutará siempre, tenga éxito o no.

Y en el método render, mostramos el mensaje de error o el mensaje de carga junto con la matriz de users desde el estado en la consola.

Ahora, si verificas la aplicación, verás la información de users en la consola sobre el éxito o un mensaje de error en la UI por falla del API.

Cómo mostrar la información de los usuarios

Ahora, mostremos la información users en la pantalla.

Crea un nuevo archivo User.js dentro de la carpeta components con el siguiente contenido:

import React from "react";

const User = ({ name, location, email, picture }) => {
  return (
    <div className="random-user">
      <div className="user-image">
        <img src={picture.medium} alt={name.first} />
      </div>
      <div className="user-details">
        <div>
          <strong>Name:</strong> {name.first} {name.last}
        </div>
        <div>
          <strong>Country:</strong> {location.country}
        </div>
        <div>
          <strong>Email:</strong> {email}
        </div>
      </div>
    </div>
  );
};

export default User;

Ahora, crea un nuevo archivo UsersList.js dentro de la carpeta components con el siguiente contenido:

import React from 'react';
import User from './User';

const UsersList = ({ users }) => {
  return (
    <div className="user-list">
      {users && users.map((user) => <User key={user.login.uuid} {...user} />)}
    </div>
  );
};

export default UsersList;

Ahora, abre el archivo App.js y reemplaza el método render con el siguiente código:

render() {
  const { users, isLoading, errorMsg } = this.state;

  return (
    <div className="main-section">
      <Header />
      {isLoading && <p className="loading">Loading...</p>}
      {errorMsg && <p className="errorMsg">{errorMsg}</p>}
      <UsersList users={users} />
    </div>
  );
}

Aquí, estamos pasando el arreglo de users como propiedades al componente UsersList. Dentro del componente UsersList, estamos recorriendo el arreglo y enviando la información del usuario al componente User mediante la distribución de todas las propiedades del user individual como {...props}. Esto finalmente muestra los datos en la pantalla.

Además, importa el componente UsersList en la parte superior del archivo:

import UsersList from './components/UsersList';

Si revisas la aplicación ahora, verás la siguiente pantalla:

random_users

Como puedes ver, en cada actualización de página, se muestra un nuevo conjunto de usuarios aleatorios en la pantalla.

Cómo implementar funcionalidad de cargar más

Ahora, agreguemos la funcionalidad de cargar más que permitirá a nuestra aplicación cargar el siguiente conjunto de 10 usuarios con cada clic de carga.

Cambia el método render del archivo App.js al siguiente código:

render() {
  const { users, isLoading, errorMsg } = this.state;

  return (
    <div className="main-section">
      <Header />
      <UsersList users={users} />
      {errorMsg && <p className="errorMsg">{errorMsg}</p>}
      <div className="load-more">
        <button onClick={this.loadMore} className="btn-grad">
          {isLoading ? 'Loading...' : 'Load More'}
        </button>
      </div>
    </div>
  );
}

Aquí, hemos agregado la condición isLoading dentro del botón para mostrar el texto Loading... o Load More en el botón.

Agrega la nueva propiedad page al estado e inicialízala en 0.

state = {
  users: [],
  page: 0,
  isLoading: false,
  errorMsg: ''
};

Y agrega la función loadMore antes del método render para incrementar el valor del estado de page en 1 en cada clic de botón.

loadMore = () => {
  this.setState((prevState) => ({
    page: prevState.page + 1
  }));
};

Aquí, estamos usando el estado anterior para calcular el siguiente valor de estado page, por lo que el código anterior es el mismo que el código siguiente:

loadMore = () => {
  this.setState((prevState) => {
    return {
      page: prevState.page + 1
    };
  });
};

Solo estamos usando la sintaxis abreviada de ES6 para devolver un objeto de la función.

Ahora, dentro del método componentDidMount, cambie la URL del API  con el código:

'https://randomuser.me/api/?page=0&results=10'

a este código:

`https://randomuser.me/api/?page=${page}&results=10`

Aquí, estamos usando la sintaxis de plantilla literal ES6 para usar el valor dinámico del estado de page para cargar el siguiente conjunto de usuarios en cada clic de botón.

Desestructuramos page desde el estado dentro del método componentDidMount de esta manera:

componentDidMount() {
  const { page } = this.state;
  ....
}

Ahora, revisemos la funcionalidad de la aplicación.

load_more_state_changing

Como puedes ver, cuando hacemos clic en el botón Load More, el estado de page está cambiando en las herramientas de desarrollo de react, pero no aparece la nueva lista de usuarios en la pantalla.

Esto se debe a que, aunque estamos cambiando el estado de page, no volvemos a realizar una llamada al API para obtener el siguiente grupo de usuarios con el valor de page modificado. Así que arreglemos esto.

Crea una nueva función loadUsers encima de la función loadMore y mueve todo el código de componentDidMount al interior de la función loadUsers. Luego llama a la función loadUsers desde el método componentDidMount.

También, agrega el método componentDidUpdate dentro del componente de la aplicación como este:

componentDidUpdate(prevProps, prevState) {
  if (prevState.page !== this.state.page) {
    this.loadUsers();
  }
}

Como estamos actualizando el valor del estado de page en la función loadMore una vez que se actualiza el estado, se llamará al método componentDidUpdate. Entonces, estamos verificando si el valor del estado anterior de page no es igual al valor del estado actual. Luego volvemos a hacer la llamada al API llamando a la función loadUsers.

Revisa el siguiente artículo para aprender más sobre por qué y cuándo necesitamos usar el método componentDidUpdate .

Tu archivo completo App.js se verá así ahora:

import React from 'react';
import Header from './components/Header';
import axios from 'axios';
import UsersList from './components/UsersList';

export default class App extends React.Component {
  state = {
    users: [],
    page: 0,
    isLoading: false,
    errorMsg: ''
  };

  componentDidMount() {
    this.loadUsers();
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevState.page !== this.state.page) {
      this.loadUsers();
    }
  }

  loadUsers = () => {
    const { page } = this.state;

    this.setState({ isLoading: true });
    axios
      .get(`https://randomuser.me/api/?page=${page}&results=10`)
      .then((response) => {
        this.setState({ users: response.data.results, errorMsg: '' });
      })
      .catch((error) =>
        this.setState({
          errorMsg: 'Error while loading data. Try again later.'
        })
      )
      .finally(() => {
        this.setState({ isLoading: false });
      });
  };

  loadMore = () => {
    this.setState((prevState) => ({
      page: prevState.page + 1
    }));
  };

  render() {
    const { users, isLoading, errorMsg } = this.state;

    return (
      <div className="main-section">
        <Header />
        <UsersList users={users} />
        {errorMsg && <p className="errorMsg">{errorMsg}</p>}
        <div className="load-more">
          <button onClick={this.loadMore} className="btn-grad">
            {isLoading ? 'Loading...' : 'Load More'}
          </button>
        </div>
      </div>
    );
  }
}

Ahora, si vuelves a comprobar la aplicación ejecutando el comando yarn start, verás la siguiente pantalla:

new_users_loaded

Como puedes ver, estamos obteniendo una nueva lista de usuarios que se muestra en cada clic de botón de carga. Pero el problema es que solo podemos ver a 10 usuarios a la vez.

Así que hagamos cambios para agregar nuevos usuarios a la lista de usuarios que ya se muestra.

Para esto, necesitamos cambiar la forma en que configuramos el estado de users.

Nuestra llamada setState actual dentro de la función loadUsers se ve así:

this.setState({ users: response.data.results, errorMsg: '' });

Aquí, siempre reemplazamos el arreglo de users con el nuevo conjunto de usuarios. Así que cambie la llamada setState anterior al siguiente código:

this.setState((prevState) => ({
  users: [...prevState.users, ...response.data.results],
  errorMsg: ''
}));

Aquí, estamos usando la sintaxis del actualizador de setState. Estamos creando un nuevo arreglo distribuyendo los users ya agregados usando ...prevState.users, y luego agregamos un nuevo conjunto de users usando ..response.data.results.

De esta manera, no perderemos los datos de los users cargados anteriormente y también podremos agregar un nuevo conjunto de users.

Ahora, si vuelves a comprobar la aplicación, verás el comportamiento correcto de la carga de datos.

correct_loading

Cómo mejorar el código usando Async/await

Si revisas la función loadUsers, verás que el código parece complejo y difícil de leer.

loadUsers = () => {
  const { page } = this.state;

  this.setState({ isLoading: true });
  axios
    .get(`https://randomuser.me/api/?page=${page}&results=10`)
    .then((response) => {
      this.setState((prevState) => ({
        users: [...prevState.users, ...response.data.results],
        errorMsg: ''
      }));
    })
    .catch((error) =>
      this.setState({
        errorMsg: 'Error while loading data. Try again later.'
      })
    )
    .finally(() => {
      this.setState({ isLoading: false });
    });
};

Podemos arreglar esto usando la sintaxis async/await.

Primero, necesitamos marcar la función loadUsers como asíncrona:

loadUsers = async () => {

Porque podemos usar la palabra clave await solo dentro de la función que se declara como async.

Ahora, reemplaza la función loadUsers con el siguiente código:

loadUsers = async () => {
  try {
    const { page } = this.state;

    this.setState({ isLoading: true });
    const response = await axios.get(
      `https://randomuser.me/api/?page=${page}&results=10`
    );

    this.setState((prevState) => ({
      users: [...prevState.users, ...response.data.results],
      errorMsg: ''
    }));
  } catch (error) {
    this.setState({
      errorMsg: 'Error while loading data. Try again later.'
    });
  } finally {
    this.setState({ isLoading: false });
  }
};

Aquí, hemos usado la palabra clave await antes de la llamada axios.get, por lo que la siguiente línea de código, que es la llamada setState, no se ejecutará hasta que obtengamos la respuesta del API.

Si hay algún error al obtener la respuesta del API, se ejecutará el bloque catch. El bloque finally establecerá el estado isLoading en false.

Tu archivo App.js modificado se verá así ahora:

import React from 'react';
import Header from './components/Header';
import axios from 'axios';
import UsersList from './components/UsersList';

export default class App extends React.Component {
  state = {
    users: [],
    page: 0,
    isLoading: false,
    errorMsg: ''
  };

  componentDidMount() {
    this.loadUsers();
  }

  componentDidUpdate(prevProps, prevState) {
    if (prevState.page !== this.state.page) {
      this.loadUsers();
    }
  }

  loadUsers = async () => {
    try {
      const { page } = this.state;

      this.setState({ isLoading: true });
      const response = await axios.get(
        `https://randomuser.me/api/?page=${page}&results=10`
      );

      this.setState((prevState) => ({
        users: [...prevState.users, ...response.data.results],
        errorMsg: ''
      }));
    } catch (error) {
      this.setState({
        errorMsg: 'Error while loading data. Try again later.'
      });
    } finally {
      this.setState({ isLoading: false });
    }
  };

  loadMore = () => {
    this.setState((prevState) => ({
      page: prevState.page + 1
    }));
  };

  render() {
    const { users, isLoading, errorMsg } = this.state;

    return (
      <div className="main-section">
        <Header />
        <UsersList users={users} />
        {errorMsg && <p className="errorMsg">{errorMsg}</p>}
        <div className="load-more">
          <button onClick={this.loadMore} className="btn-grad">
            {isLoading ? 'Loading...' : 'Load More'}
          </button>
        </div>
      </div>
    );
  }
}

Ahora, el código de la función loadUsers parece mucho más limpio y más fácil de entender que antes. Y si revisas la aplicación, verás que también está funcionando correctamente.

correct_loading-1

Cómo refactorizar el código de componente de clase en código de componente funcional

Hemos terminado de desarrollar la funcionalidad completa de la aplicación. Así que refactoricemos el código para usar componentes funcionales con React Hooks.

Si eres nuevo en React Hooks, revisa el siguiente articulo para una introducción a los Hooks.

Crea un nuevo archivo llamado AppFunctional.js dentro de la carpeta src con el siguiente contenido:

import React from 'react';

const AppFunctional = () => {
  return (
    <div>
      <h2>Functional Component</h2>
    </div>
  );
};

export default AppFunctional;

Hemos creado un nuevo archivo para el componente funcional para que pueda comparar el código y guardarlo para su referencia.

Ahora, abre el archivo index.js y reemplaza el contenido del archivo con el siguiente código:

import React from 'react';
import ReactDOM from 'react-dom';
import AppFunctional from './AppFunctional';
import './styles.css';

ReactDOM.render(<AppFunctional />, document.getElementById('root'));

Aquí, hemos utilizado el componente AppFunctional dentro del método render y también hemos agregado la importación para él mismo en la parte superior del archivo.

Ahora, si vuelves a arrancar tu aplicación usando el comando yarn start, verás la siguiente pantalla:

functional_component

Entonces, estamos mostrando correctamente el código del componente AppFunctional en la pantalla.

Ahora, reemplace el contenido del componente AppFunctional con el siguiente código:

import React, { useState, useEffect } from 'react';
import axios from 'axios';
import Header from './components/Header';
import UsersList from './components/UsersList';

const AppFunctional = () => {
  const [users, setUsers] = useState([]);
  const [page, setPage] = useState(0);
  const [isLoading, setIsLoading] = useState(false);
  const [errorMsg, setErrorMsg] = useState('');

  useEffect(() => {
    const loadUsers = async () => {
      try {
        setIsLoading(true);
        const response = await axios.get(
          `https://randomuser.me/api/?page=${page}&results=10`
        );

        setUsers([...users, ...response.data.results]);
        setErrorMsg('');
      } catch (error) {
        setErrorMsg('Error while loading data. Try again later.');
      } finally {
        setIsLoading(false);
      }
    };

    loadUsers();
  }, []);

  const loadMore = () => {
    setPage((page) => page + 1);
  };

  return (
    <div className="main-section">
      <Header />
      <UsersList users={users} />
      {errorMsg && <p className="errorMsg">{errorMsg}</p>}
      <div className="load-more">
        <button onClick={loadMore} className="btn-grad">
          {isLoading ? 'Loading...' : 'Load More'}
        </button>
      </div>
    </div>
  );
};

export default AppFunctional;

Aquí, inicialmente declaramos los estados requeridos usando el hook useState:

const [users, setUsers] = useState([]);
const [page, setPage] = useState(0);
const [isLoading, setIsLoading] = useState(false);
const [errorMsg, setErrorMsg] = useState('');

Luego agregamos un hook useEffect y le pasamos un arreglo vacío [] como segundo argumento. Esto significa que el código dentro del hook useEffect se ejecutará solo una vez cuando se monte el componente.

useEffect(() => {
 // your code
}, []);

Hemos trasladado toda la función loadUsers dentro del hook useEffect y luego la llamamos dentro del gancho de esta manera:

useEffect(() => {
  const loadUsers = async () => {
    // your code
  };

  loadUsers();
}, []);

También hemos eliminado todas las referencias a this.state ya que los componentes funcionales no necesitan el contexto this.

Antes de realizar la llamada al API, establecemos el estado isLoading en true usando setIsLoading(true);.

Como ya tenemos acceso al arreglo de users dentro del componente, estamos configurando directamente como una nuevo arreglo para la función setUsers de esta manera:

setUsers([...users, ...response.data.results]);
Si quieres saber porqué no podemos usar la palabra clave async directamente en la función hook useEffect, revisa el siguiente articulo.

Luego, hemos cambiado la función loadMore de éste código:

loadMore = () => {
  this.setState((prevState) => ({
    page: prevState.page + 1
  }));
};

a éste código:

const loadMore = () => {
  setPage((page) => page + 1);
};
Tenga en cuenta que para declarar una función basada en componentes funcionales, debe agregar const o let antes de la declaración. Como la función no va a cambiar, se recomienda usar const por ejemplo const loadMore = () => {}.

Luego, copiamos el contenido del método render tal como está dentro del componente AppFunctional para devolver el JSX. También hemos cambiado onClick = {this.loadMore} a onClick = {loadMore}.

return (
  <div className="main-section">
    <Header />
    <UsersList users={users} />
    {errorMsg && <p className="errorMsg">{errorMsg}</p>}
    <div className="load-more">
      <button onClick={loadMore} className="btn-grad">
        {isLoading ? 'Loading...' : 'Load More'}
      </button>
    </div>
  </div>
);

Ahora, si revisas la aplicación, verás la siguiente pantalla:

functional_load_more_not_working

Como puedes ver, los usuarios se están cargando correctamente, pero la funcionalidad de carga más no funciona.

Esto se debe a que solo estamos haciendo la llamada al API una vez cuando el componente está montado, ya que estamos pasando el arreglo de dependencia vacía [] como segundo argumento para el hook useEffect.

Para hacer la llamada al API nuevamente cuando cambia el estado de page, necesitamos agregar la page como una dependencia para el hook useEffect como este:

useEffect(() => {
  // execute the code to load users
}, [page]);

El useEffect anterior es lo mismo que escribir el siguiente código:

componentDidUpdate(prevProps, prevState) {
  if (prevState.page !== this.state.page) {
    // execute the code to load users
  }
}

useEffect hace que sea realmente fácil escribir menos código que sea fácil de entender.

Entonces, ahora con este cambio, el código dentro del hook useEffect se ejecutará cuando el componente se monte y cuando se cambie el estado page.

Ahora, si revisas la aplicación, verás que la funcionalidad de carga más está funcionando nuevamente como se esperaba.

correct_loading-2

Pero si verificas la terminal/símbolo del sistema, es posible que observes una advertencia como se muestra a continuación (si tienes ESLint instalado en su máquina):

eslint_warning

Estas advertencias nos ayudan a evitar problemas en nuestra aplicación que podrían ocurrir más adelante, por lo que siempre es bueno solucionarlos si es posible.

Como estamos haciendo referencia al estado de users dentro de la función loadUsers, debemos incluirlo también en en arreglo de dependencia. Así que hagámoslo.

Incluye a los users como una dependencia junto con page como se muestra a continuación:

useEffect(() => {
  // your code
}, [page, users]);

Comprobemos ahora la funcionalidad de la aplicación.

infinite_loop

Como puedes ver, continuamente estamos obteniendo un nuevo conjunto de usuarios a medida que nos desplazamos por la página y la aplicación avanza en un bucle infinito.

Esto se debe a que cuando se monta el componente, el código dentro del hook useEffect se ejecutará para realizar una llamada al API. Una vez que obtenemos el resultado, configuramos el arreglo de users.

Como los users son mencionados en la lista de dependencias, una vez que se cambia el arreglo de usuarios, useEffect se ejecutará nuevamente y sucederá una y otra vez creando un bucle infinito.

Entonces, para solucionar esto, debemos evitar hacer referencia al arreglo de users externos de alguna manera. Para hacer eso, usemos la sintaxis del actualizador de setState para configurar el estado de users.

Por lo tanto, cambia el siguiente código:

setUsers([...users, ...response.data.results]);

a este código:

setUsers((users) => [...users, ...response.data.results]);

Aquí, estamos usando el valor anterior de users para crear un nuevo arreglo de users.

Ahora, podemos eliminar los users del arreglo de dependencias de useEffect ya que no estamos haciendo referencia a la variable externa users.

Tu hook useEffect modificado se verá así ahora:

useEffect(() => {
  const loadUsers = async () => {
    try {
      setIsLoading(true);
      const response = await axios.get(
        `https://randomuser.me/api/?page=${page}&results=10`
      );

      setUsers((users) => [...users, ...response.data.results]);
      setErrorMsg('');
    } catch (error) {
      setErrorMsg('Error while loading data. Try again later.');
    } finally {
      setIsLoading(false);
    }
  };

  loadUsers();
}, [page]);

Si revisas la aplicación ahora, verás funciona como se esperaba sin ningún problema.

correct_loading-3

Y ahora tampoco estamos recibiendo ningún error en la terminal.

no_error

¡Gracias por leer!

Puedes encontrar el código fuente completo para esta aplicación en este repositorio y una demostración en vivo de la aplicación implementada aquí.

Traducido del artículo de Yogesh Chavan - How to Build a React Application with Load More Functionality using React Hooks