<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/"
    xmlns:atom="http://www.w3.org/2005/Atom" xmlns:media="http://search.yahoo.com/mrss/" version="2.0">
    <channel>
        
        <title>
            <![CDATA[ Juan C. Guaña - freeCodeCamp.org ]]>
        </title>
        <description>
            <![CDATA[ Descubre miles de cursos de programación escritos por expertos. Aprende Desarrollo Web, Ciencia de Datos, DevOps, Seguridad y obtén asesoramiento profesional para desarrolladores. ]]>
        </description>
        <link>https://www.freecodecamp.org/espanol/news/</link>
        <image>
            <url>https://cdn.freecodecamp.org/universal/favicons/favicon.png</url>
            <title>
                <![CDATA[ Juan C. Guaña - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/espanol/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Fri, 22 May 2026 15:16:28 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/espanol/news/author/juancguana/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Cómo recuperar datos en React: hoja de trucos + ejemplos ]]>
                </title>
                <description>
                    <![CDATA[ Hay muchas formas de recuperar datos de una API externa en React. Pero, ¿cuál debería utilizar para sus aplicaciones en 2021? En este tutorial, revisaremos cinco de los patrones más utilizados para recuperar datos con React realizando una solicitud HTTP a una API REST. No solo cubriremos cómo recuperar datos, ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-recuperar-datos-en-react-hoja-de-trucos-ejemplos/</link>
                <guid isPermaLink="false">66ace90684629203fb40d987</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan C. Guaña ]]>
                </dc:creator>
                <pubDate>Tue, 13 Aug 2024 15:33:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/08/how-to-fetch-data-in-react.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/fetch-data-react/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Fetch Data in React: Cheat Sheet + Examples</a>
      </p><p>Hay muchas formas de recuperar datos de una API externa en React. Pero, ¿cuál debería utilizar para sus aplicaciones en 2021?</p><p>En este tutorial, revisaremos cinco de los patrones más utilizados para recuperar datos con React realizando una solicitud HTTP a una API REST.</p><p>No solo cubriremos cómo recuperar datos, sino también cómo manejar mejor la carga y el estado de error al recuperar nuestros datos.</p><p>¡Empecemos!</p><blockquote>Para todos estos ejemplos, usaremos un endpoint del popular JSON Placeholder API, pero puedes usar su propia API que haya creado (como una API de Node con Express) o cualquier otra API pública.</blockquote><h3></h3><h2 id="1-c-mo-recuperar-datos-en-react-usando-la-api-fetch"><strong>1. Cómo Recuperar Datos en React Usando la API Fetch</strong></h2><p>La forma más accesible de recuperar datos con React es utilizar la API Fetch.</p><p>Fetch API es una herramienta integrada en la mayoría de los navegadores modernos en el objeto window ( <code>window.fetch</code>) y nos permite realizar solicitudes HTTP muy fácilmente utilizando promesas de JavaScript.</p><p>Para realizar una solicitud GET simple con fetch solo necesitamos incluir la URL del endpoint al que queremos realizar nuestra solicitud. Queremos realizar esta solicitud una vez que nuestro componente React se haya montado.</p><p>Para hacerlo, realizamos nuestra solicitud dentro del hook useEffect y nos aseguramos de proporcionar un arreglo de dependencias vacía como segundo argumento, de modo que nuestra solicitud solo se realice una vez (asumiendo que no depende de ningún otro dato en nuestro componente).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/clip-1-fetch-min.gif" class="kg-image" alt="clip-1-buscar-min" width="600" height="400" loading="lazy"></figure><p>En el primer callback <code>.then()</code>, verificamos si la respuesta fue correcta ( <code>response.ok</code>). Si es así, devolvemos nuestra respuesta para pasar a la siguiente, luego volvemos a llamar como datos JSON, ya que esos son los datos que obtendremos de nuestra API de usuario aleatorio.</p><p>Si no es una respuesta correcta, asumimos que hubo un error al realizar la solicitud. Al usar fetch, necesitamos manejar los errores nosotros mismos, por lo que lo arrojamos <code>response</code>como un error para que nuestro callback <code>catch</code> lo maneje.</p><p>Aquí, en nuestro ejemplo, colocamos nuestros datos de error en el estado con <code>setError</code>. Si hay un error, devolvemos el texto "¡Error!".</p><blockquote>Tenga en cuenta que también puede mostrar un mensaje de error del objeto de error que pusimos en estado usando <code>error.message</code>.</blockquote><p>Usamos el callback <code>.finally()</code> como función que se llama cuando nuestra promesa se resolvió exitosamente o no. En él, lo configuramos <code>loading</code>en falso, para que ya no veamos nuestro texto de carga.</p><p>En su lugar, vemos nuestros datos en la página si la solicitud se realizó correctamente o si hubo un error al realizar la solicitud.</p><h2 id="2-c-mo-recuperar-datos-en-react-usando-axios"><strong>2. Cómo Recuperar Datos en React Usando Axios</strong></h2><p>El segundo enfoque para realizar solicitudes con React es utilizar la librería <code>axios</code>.</p><p>En este ejemplo, simplemente revisaremos nuestro ejemplo de Fetch instalando primero <code>axios</code>usando npm:</p><pre><code class="language-bash">npm install axios</code></pre><p>Luego lo importaremos en la parte superior de nuestro archivo de componente.</p><p>Lo que axios nos permite hacer es usar exactamente la misma sintaxis de promesa que fetch, pero en lugar de usar nuestra devolución de llamada primero y luego para determinar manualmente si la respuesta es correcta y arrojar un error, axios se encarga de eso por nosotros.</p><p>Además, nos permite en esa primera devolución de llamada obtener los datos JSON de <code>response.data</code>.</p><p>Lo conveniente de usar axios es que tiene una sintaxis mucho más corta que nos permite reducir nuestro código e incluye muchas herramientas y características que Fetch no tiene en su API.</p><p>Todas estas razones son las que se han convertido en la librería HTTP de referencia para los desarrolladores de React.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/clip-2-axios-min.gif" class="kg-image" alt="clip-2-axios-min" width="600" height="400" loading="lazy"></figure><h2 id="3-c-mo-recuperar-datos-en-react-usando-la-sintaxis-async-await"><strong>3. Cómo recuperar datos en React Usando la Sintaxis async/await</strong></h2><p>En ES7, fue posible resolver promesas utilizando la sintaxis <code>async / await</code>.</p><p>El beneficio de esto es que nos permite eliminar los callback <code>.then()</code>, <code>.catch()</code>y <code>.finally()</code> simplemente recupera nuestros datos resueltos asincrónicamente como si estuviéramos escribiendo código síncrono sin ninguna promesa.</p><p>En otras palabras, no tenemos que depender de devoluciones de llamada cuando usamos async/await con React.</p><p>Tenemos que ser conscientes del hecho de que cuando usamos <code>useEffect</code>, la función de efecto (el primer argumento) no puede convertirse en una <code>async</code> función.</p><p>Si echamos un vistazo al error de linting que nos da React si estábamos usando Create React App para construir nuestro proyecto, se nos dirá que esta función no puede ser asincrónica para evitar condiciones de carrera.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/clip-3-async-await-min.gif" class="kg-image" alt="clip-3-async-espera-min" width="600" height="400" loading="lazy"></figure><p>Como resultado, en lugar de hacer que esa función sea asíncrona, simplemente podemos crear una función asíncrona separada en nuestro componente, a la que podemos llamar sincrónicamente. Es decir, sin la palabra clave <code>await</code> &nbsp;delante.</p><p>En este ejemplo, creamos una función asíncrona llamada <code>getData</code>. Al llamarlo sincrónicamente dentro de useEffect, podemos recuperar nuestros datos como esperábamos.</p><h2 id="4-c-mo-recuperar-datos-en-react-usando-un-hook-de-react-personalizado-usefetch-"><strong>4. Cómo Recuperar Datos en React Usando un Hook de React Personalizado (useFetch)</strong></h2><p>Con el tiempo, es posible que te des cuenta de que se vuelve un poco tedioso y lleva mucho tiempo seguir escribiendo el hook useEffect con todo su texto estándar dentro de cada componente en el que desea recuperar datos.</p><p>Para reducir nuestro código reutilizado, podemos usar un hook personalizado como una abstracción especial, que podemos escribir nosotros mismos desde una librería de terceros (como estamos aquí, usando la librería <code>react-fetch-hook</code>).</p><p>Un hook personalizado que realiza nuestra solicitud HTTP nos permite hacer que nuestros componentes sean mucho más concisos. Todo lo que tenemos que hacer es llamar a nuestro hook en la parte superior de nuestro componente.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/clip-4-usefetch-min.gif" class="kg-image" alt="clip-4-usefetch-min" width="600" height="400" loading="lazy"></figure><p>En este caso, recuperamos todos los datos, la carga y el estado de error que necesitamos para poder usar la misma estructura para nuestro componente que antes, pero sin tener que hacerlo con <code>useEffect</code>. Además, ya no necesitamos escribir imperativamente cómo resolver nuestra promesa de nuestra solicitud GET cada vez que queremos realizar una solicitud.</p><h2 id="5-c-mo-recuperar-datos-en-react-usando-la-librer-a-react-query"><strong>5. Cómo Recuperar Datos en React Usando la L</strong>ibrería<strong> React Query</strong></h2><p>El uso de hooks personalizados es una excelente manera de escribir solicitudes HTTP mucho más concisas para obtener nuestros datos y todo su estado relacionado. Pero una librería que realmente lleva la recuperación de datos con hooks al siguiente nivel es React Query.</p><p>React Query no solo nos permite usar hooks personalizados que podemos reutilizar en nuestros componentes de manera concisa, sino que también nos brinda una gran cantidad de herramientas de administración de estado para poder controlar cuándo, cómo y con qué frecuencia se obtienen nuestros datos.</p><p>En particular, React query nos proporciona un caché, que puede ver a continuación a través de React Query Devtools. Esto nos permite gestionar fácilmente las solicitudes que hemos realizado según el valor clave que especificamos para cada solicitud.</p><p>Para las solicitudes siguientes, nuestra consulta de datos de usuario aleatorios se identifica mediante la cadena 'random-user' (proporcionada como primer argumento de <code>useQuery</code>).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/03/clip-5-react-query-min.gif" class="kg-image" alt="clip-5-reaccionar-consulta-min" width="600" height="400" loading="lazy"></figure><p>Al hacer referencia a esa clave, podemos hacer cosas poderosas como recuperar, validar o restablecer nuestras diversas consultas.</p><blockquote>Si confiamos en nuestra solución de hook personalizada o useEffect, recuperaremos nuestros datos cada vez que se monte nuestro componente. En la mayoría de los casos, hacer esto es innecesario. Si nuestro estado externo no ha cambiado, idealmente no deberíamos tener que mostrar el estado de carga cada vez que mostramos nuestro componente.</blockquote><p>React Query mejora enormemente nuestra experiencia de usuario al intentar servir nuestros datos desde su caché primero y luego actualizar los datos en segundo plano para mostrar los cambios si el estado de nuestra API ha cambiado.</p><p>También nos brinda un arsenal de herramientas poderosas para administrar mejor nuestras solicitudes de acuerdo con cómo cambian nuestros datos a través de nuestra solicitud.</p><p>Por ejemplo, si nuestra aplicación nos permitió agregar un usuario diferente, es posible que queramos recuperar esa consulta una vez que se agregó el usuario. Si supiéramos que la consulta se cambia con mucha frecuencia, es posible que deseemos especificar que se actualice aproximadamente cada minuto. O para actualizarse cada vez que el usuario enfoque la pestaña de su ventana.</p><p>En resumen, React Query es la solución ideal no solo para realizar solicitudes de manera concisa, sino también para administrar de manera eficiente y efectiva los datos que se devuelven para nuestras solicitudes HTTP en todos los componentes de nuestra aplicación.</p><h2 id="-quiere-conservar-esta-gu-a-para-consultarla-en-el-futuro"><strong>¿Quiere conservar esta guía para consultarla en el futuro?</strong></h2><p>Aquí hay 3 ganancias rápidas que obtienes cuando obtienes la versión descargable:</p><ul><li>Obtendrá toneladas de fragmentos de código copiables para reutilizarlos fácilmente en sus propios proyectos.</li><li>Es una excelente guía de referencia para fortalecer tus habilidades como desarrollador de React y para entrevistas de trabajo.</li><li>Puede llevar, utilizar, imprimir, leer y releer esta guía literalmente donde quiera.</li></ul><h2 id="convi-rtete-en-un-desarrollador-profesional-de-react"><strong>Conviértete en un Desarrollador Profesional de React</strong></h2><p>React es difícil. No deberías tener que resolverlo tú mismo.</p><p>He reunido todo lo que sé sobre React en un solo curso para ayudarte a alcanzar tus objetivos en un tiempo récord:</p><p><strong><strong><a href="https://www.thereactbootcamp.com/">Presentamos: El Bootcamp de React</a></strong></strong></p><p><strong><strong>Es el único curso que desearía tener cuando comencé a aprender React.</strong></strong></p><p>Haga clic a continuación para probar React Bootcamp usted mismo:</p><figure class="kg-card kg-image-card"><img src="https://reedbarger.nyc3.digitaloceanspaces.com/reactbootcamp/react-bootcamp-cta-alt.png" class="kg-image" alt="Haga clic para unirse al Bootcamp de React" width="600" height="400" loading="lazy"></figure><p><br><em><em><a href="https://www.thereactbootcamp.com/">Haga clic para comenzar</a></em></em></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo usar Axios con React: La guía definitiva (2021) ]]>
                </title>
                <description>
                    <![CDATA[ En esta guía, aprenderás cómo usar Axios.js con React usando toneladas de ejemplos del mundo real con hooks de React. Veras por qué debería usar Axios como una biblioteca de obtención de datos, cómo configurarlo con React y realizar todo tipo de solicitud HTTP con él. Luego, hablaremos de funciones ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-usar-axios-con-react/</link>
                <guid isPermaLink="false">6206f6608c84bc08e443afbc</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan C. Guaña ]]>
                </dc:creator>
                <pubDate>Thu, 14 Jul 2022 20:47:50 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2022/02/how-to-use-axios-with-react.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-use-axios-with-react/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How To Use Axios With React: The Definitive Guide (2021)</a>
      </p><p>En esta guía, aprenderás cómo usar Axios.js con React usando toneladas de ejemplos del mundo real con hooks de React.</p><p>Veras por qué debería usar Axios como una biblioteca de obtención de datos, cómo configurarlo con React y realizar todo tipo de solicitud HTTP con él.</p><p>Luego, hablaremos de funciones más avanzadas, como la creación de una instancia de Axios para la reutilización, el uso de async-await con Axios para simplificar y cómo usar Axios como un hook personalizado.</p><p>Empecemos!</p><h2 id="tabla-de-contenido"><strong>Tabla de contenido</strong></h2><ul><li><a href="https://www.freecodecamp.org/espanol/news/p/fff67b93-ab1b-452e-b579-6957bdfe13b4/#axios">¿Qué es Axios?</a></li><li><a href="https://www.freecodecamp.org/espanol/news/p/fff67b93-ab1b-452e-b579-6957bdfe13b4/#por-qu-usar-axios-en-react">¿Por qué usar Axios en React?</a></li><li><a href="https://www.freecodecamp.org/espanol/news/p/fff67b93-ab1b-452e-b579-6957bdfe13b4/#c-mo-configurar-axios-con-react">Cómo configurar Axios con React</a></li><li><a href="https://www.freecodecamp.org/espanol/news/p/fff67b93-ab1b-452e-b579-6957bdfe13b4/#c-mo-hacer-una-solicitud-get">Cómo hacer una solicitud GET (recuperar datos)</a></li><li><a href="https://www.freecodecamp.org/espanol/news/p/fff67b93-ab1b-452e-b579-6957bdfe13b4/#c-mo-hacer-una-solicitud-post">Cómo hacer una solicitud POST (Crear datos)</a></li><li><a href="https://www.freecodecamp.org/espanol/news/p/fff67b93-ab1b-452e-b579-6957bdfe13b4/#c-mo-hacer-una-solicitud-put">Cómo hacer una solicitud PUT (Actualizar datos)</a></li><li><a href="https://www.freecodecamp.org/espanol/news/p/fff67b93-ab1b-452e-b579-6957bdfe13b4/#c-mo-hacer-una-solicitud-de-eliminaci-n">Cómo hacer una solicitud DELETE (Borrar datos)</a></li><li><a href="https://www.freecodecamp.org/espanol/news/p/fff67b93-ab1b-452e-b579-6957bdfe13b4/#c-mo-manejar-errores-con-axios">Cómo manejar errores con Axios</a></li><li><a href="https://www.freecodecamp.org/espanol/news/p/fff67b93-ab1b-452e-b579-6957bdfe13b4/#c-mo-crear-una-instancia-de-axios">Cómo crear una instancia de Axios</a></li><li><a href="https://www.freecodecamp.org/espanol/news/p/fff67b93-ab1b-452e-b579-6957bdfe13b4/#c-mo-usar-la-sintaxis-async-await-con-axios">Cómo usar la sintaxis Async-Await con Axios</a></li><li><a href="https://www.freecodecamp.org/espanol/news/p/fff67b93-ab1b-452e-b579-6957bdfe13b4/#c-mo-crear-un-hook-useaxios-personalizado">Cómo crear un hook <code>useAxios</code> personalizado</a></li></ul><!--kg-card-begin: html--><h2 id="axios">¿Qué es Axios?</h2>
<!--kg-card-end: html--><p>Axios es una biblioteca de cliente HTTP que le permite realizar solicitudes a un endpoint determinado:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/07/Screen-Shot-2021-07-12-at-1.14.41-PM.png" class="kg-image" alt="Screen-Shot-2021-07-12-at-1.14.41-PM" width="600" height="400" loading="lazy"></figure><p>Esto podría ser una API externa o su propio servidor backend Node.js, por ejemplo.</p><p>Al realizar una solicitud, se espera que su API realice una operación de acuerdo con la solicitud que realizaste.</p><p>Por ejemplo, si realizas una solicitud GET, esperas obtener datos para mostrar en su aplicación.</p><h2 id="por-qu-usar-axios-en-react"><strong>Por qué usar Axios en React</strong></h2><p>Hay varias bibliotecas diferentes que puede usar para realizar estas solicitudes, entonces, ¿por qué elegir Axios?</p><p>Aquí hay <strong>cinco razones</strong> por las que debería usar Axios como su cliente para realizar solicitudes HTTP:</p><ol><li>Tiene buenos valores predeterminados para trabajar con datos JSON. A diferencia de alternativas como Fetch API, a menudo no necesita configurar sus encabezados. O realice tareas tediosas como convertir el cuerpo de su solicitud en una cadena JSON.</li><li>Axios tiene nombres de funciones que coinciden con cualquier método HTTP. Para realizar una solicitud GET, utiliza el método <code>.get()</code>.</li><li>Axios hace más con menos código. A diferencia de Fetch API, solo necesita una devolución de llamada <code>.then()</code> para acceder a los datos JSON solicitados.</li><li>Axios tiene un mejor manejo de errores. Axios arroja 400 y 500 errores de rango por nosotros. A diferencia de Fetch API, donde debe verificar el código de estado y arrojar el error nosotros mismo.</li><li>Axios se puede utilizar tanto en el servidor como en el cliente. Si está escribiendo una aplicación en Node.js, tenga en cuenta que Axios también se puede usar en un entorno separado del navegador.</li></ol><h2 id="c-mo-configurar-axios-con-react"><strong>Cómo configurar Axios con React</strong></h2><p>Usar Axios con React es un proceso muy simple. Necesitas tres cosas:</p><ol><li>Un proyecto React existente</li><li>Para instalar Axios con npm/yarn</li><li>Un endpoint API para realizar solicitudes</li></ol><p>La forma más rápida de crear una nueva aplicación React es yendo a <a href="https://react.new/">react.new</a>.</p><p>Si tienes un proyecto React existente, solo necesita instalar Axios con npm (o cualquier otro administrador de paquetes):</p><pre><code class="language-bash">npm install axios</code></pre><p>En esta guía, utilizarás la API de JSON Placeholder para obtener y cambiar los datos de las publicaciones.</p><p>Aquí hay una lista de todas las diferentes rutas a las que puede realizar solicitudes, junto con el método HTTP apropiado para cada una:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/07/Screen-Shot-2021-07-10-at-12.21.28-PM.png" class="kg-image" alt="Screen-Shot-2021-07-10-at-12.21.28-PM" width="600" height="400" loading="lazy"></figure><p>Aquí hay un ejemplo rápido de todas las operaciones que realizarás con Axios y endpoint API: — recuperar, crear, actualizar y eliminar publicaciones:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/07/axios-react.gif" class="kg-image" alt="axios-react" width="600" height="400" loading="lazy"></figure><h2 id="c-mo-hacer-una-solicitud-get"><strong>Cómo hacer una solicitud GET</strong></h2><p>Para obtener datos o recuperarlos, realiza una solicitud GET.</p><p>Primero, vas a hacer una solicitud de publicaciones individuales. Si observa el endpoint, obtendrás la primera publicación del endpoint /posts:</p><pre><code class="language-js">import axios from "axios";
import React from "react";

const baseURL = "https://jsonplaceholder.typicode.com/posts/1";

export default function App() {
  const [post, setPost] = React.useState(null);

  React.useEffect(() =&gt; {
    axios.get(baseURL).then((response) =&gt; {
      setPost(response.data);
    });
  }, []);

  if (!post) return null;

  return (
    &lt;div&gt;
      &lt;h1&gt;{post.title}&lt;/h1&gt;
      &lt;p&gt;{post.body}&lt;/p&gt;
    &lt;/div&gt;
  );
}</code></pre><p>Para realizar esta solicitud, cuando se monta el componente, utiliza el hook useEffect. Esto implica importar Axios, usar el método <code>.get()</code> para realizar una solicitud GET a su endpoint y usar el callback <code>.then()</code> para recuperar todos los datos de respuesta.</p><p>Note that you can always find the requested data from the <code>.data</code> property in the response. Ten en cuenta que siempre puede encontrar los datos solicitados de la propiedad <code>.data</code> en la respuesta.</p><h2 id="c-mo-hacer-una-solicitud-post"><strong>Cómo hacer una solicitud POST</strong></h2><p>Para crear nuevos datos, realiza una solicitud POST.</p><p>De acuerdo con la API, esto debe realizarse hacia el endpoint <code>/posts</code>. Si observas el código a continuación, verás que hay un botón para crear una publicación:</p><pre><code class="language-js">import axios from "axios";
import React from "react";

const baseURL = "https://jsonplaceholder.typicode.com/posts";

export default function App() {
  const [post, setPost] = React.useState(null);

  React.useEffect(() =&gt; {
    axios.get(`${baseURL}/1`).then((response) =&gt; {
      setPost(response.data);
    });
  }, []);

  function createPost() {
    axios
      .post(baseURL, {
        title: "Hello World!",
        body: "This is a new post."
      })
      .then((response) =&gt; {
        setPost(response.data);
      });
  }

  if (!post) return "No post!"

  return (
    &lt;div&gt;
      &lt;h1&gt;{post.title}&lt;/h1&gt;
      &lt;p&gt;{post.body}&lt;/p&gt;
      &lt;button onClick={createPost}&gt;Create Post&lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre><p>Cuando haces clic en el botón, llama a la función <code>createPost</code>.</p><p>Para realizar esa solicitud POST con Axios, utiliza el método <code>.post()</code>. Como segundo argumento, incluye una propiedad de objeto que especifica cómo deseas que sea la nueva publicación.</p><p>Una vez más, usa el callback <code>.then()</code> para recuperar los datos de respuesta y reemplaza la primera publicación que recibiste con la nueva publicación que solicitaste.</p><p>Esto es muy similar al método <code>.get()</code>, pero el nuevo recurso que deseas crear se proporciona como el segundo argumento después del endpoint del API.</p><h2 id="c-mo-hacer-una-solicitud-put"><strong>Cómo hacer una solicitud PUT</strong></h2><p>Para actualizar un recurso determinado, realiza una solicitud PUT.</p><p>En este caso, actualizarás la primera publicación.</p><p>Para ello, volverás a crear un botón. Pero esta vez, el botón llamará a una función para actualizar una publicación:</p><pre><code class="language-js">import axios from "axios";
import React from "react";

const baseURL = "https://jsonplaceholder.typicode.com/posts";

export default function App() {
  const [post, setPost] = React.useState(null);

  React.useEffect(() =&gt; {
    axios.get(`${baseURL}/1`).then((response) =&gt; {
      setPost(response.data);
    });
  }, []);

  function updatePost() {
    axios
      .put(`${baseURL}/1`, {
        title: "Hello World!",
        body: "This is an updated post."
      })
      .then((response) =&gt; {
        setPost(response.data);
      });
  }

  if (!post) return "No post!"

  return (
    &lt;div&gt;
      &lt;h1&gt;{post.title}&lt;/h1&gt;
      &lt;p&gt;{post.body}&lt;/p&gt;
      &lt;button onClick={updatePost}&gt;Update Post&lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre><p>En el código anterior, utilizaste el método PUT de Axios. Y al igual que con el método POST, incluye las propiedades que deseas que estén en el recurso actualizado.</p><p>Nuevamente, usando la devolución de llamada <code>.then()</code>, actualiza el JSX con los datos que se devuelven.</p><h2 id="c-mo-hacer-una-solicitud-de-eliminaci-n"><strong>Cómo hacer una solicitud de ELIMINACIÓN</strong></h2><p>Finalmente, para eliminar un recurso, utiliza el método DELETE.</p><p>Como ejemplo, eliminaremos la primera publicación.</p><p>Ten en cuenta que no necesitas ningún segundo argumento para realizar esta solicitud:</p><pre><code class="language-js">import axios from "axios";
import React from "react";

const baseURL = "https://jsonplaceholder.typicode.com/posts";

export default function App() {
  const [post, setPost] = React.useState(null);

  React.useEffect(() =&gt; {
    axios.get(`${baseURL}/1`).then((response) =&gt; {
      setPost(response.data);
    });
  }, []);

  function deletePost() {
    axios
      .delete(`${baseURL}/1`)
      .then(() =&gt; {
        alert("Post deleted!");
        setPost(null)
      });
  }

  if (!post) return "No post!"

  return (
    &lt;div&gt;
      &lt;h1&gt;{post.title}&lt;/h1&gt;
      &lt;p&gt;{post.body}&lt;/p&gt;
      &lt;button onClick={deletePost}&gt;Delete Post&lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre><p>En la mayoría de los casos, no necesita los datos que se devuelven desde el método <code>.delete()</code>.</p><p>Pero en el código anterior, el callback <code>.then()</code> todavía se usa para garantizar que su solicitud se resuelva con éxito.</p><p>En el código anterior, después de eliminar una publicación, se alerta al usuario de que se eliminó correctamente. Luego, los datos de la publicación se borran del estado al configurarlos en su valor inicial de <code>null</code>.</p><p>Además, una vez que se elimina una publicación, el texto "No post" se muestra inmediatamente después del mensaje de alerta.</p><h2 id="c-mo-manejar-errores-con-axios"><strong>Cómo manejar errores con Axios</strong></h2><p>¿Qué pasa con el manejo de errores con Axios?</p><p>¿Qué pasa si hay un error al hacer una solicitud? Por ejemplo, es posible que transmita datos incorrectos, realizar una solicitud al endpoint incorrecto o tener un error de red.</p><p>Para simular un error, enviarás una solicitud a un extremo de la API que no existe: <code>/posts/asdf</code>.</p><p>Esta solicitud devolverá un código de estado <code>404</code>:</p><pre><code class="language-js">import axios from "axios";
import React from "react";

const baseURL = "https://jsonplaceholder.typicode.com/posts";

export default function App() {
  const [post, setPost] = React.useState(null);
  const [error, setError] = React.useState(null);

  React.useEffect(() =&gt; {
    // invalid url will trigger an 404 error
    axios.get(`${baseURL}/asdf`).then((response) =&gt; {
      setPost(response.data);
    }).catch(error =&gt; {
      setError(error);
    });
  }, []);
  
  if (error) return `Error: ${error.message}`;
  if (!post) return "No post!"

  return (
    &lt;div&gt;
      &lt;h1&gt;{post.title}&lt;/h1&gt;
      &lt;p&gt;{post.body}&lt;/p&gt;
    &lt;/div&gt;
  );
}</code></pre><p>En este caso, en lugar de ejecutar el callback <code>.then()</code>, Axios generará un error y ejecutará el callback <code>.catch()</code>.</p><p>En esta función, estamos tomando los datos del error y poniéndolos en estado para alertar a nuestro usuario sobre el error. Entonces, si tenemos un error, mostraremos ese mensaje de error.</p><p>Cuando ejecutes este código de código, verás el texto "Error: Request failed with status code 404".</p><h2 id="c-mo-crear-una-instancia-de-axios"><strong>Cómo crear una instancia de Axios</strong></h2><p>Si observas los ejemplos anteriores, verá que hay una <code>baseURL</code> que usamos como parte del endpoint para que Axios realice estas solicitudes.</p><p>Sin embargo, se vuelve un poco tedioso seguir escribiendo esa <code>baseURL</code> para cada solicitud. ¿No podría simplemente hacer que Axios recuerde qué <code>baseURL</code> está usando, ya que siempre involucra un punto final similar?</p><p>De hecho, puedes. Si creas una instancia con el método <code>.create()</code>, Axios recordará esa <code>baseURL</code>, además de otros valores que quizás desees especificar para cada solicitud, incluidos los encabezados:</p><pre><code class="language-js">import axios from "axios";
import React from "react";

const client = axios.create({
  baseURL: "https://jsonplaceholder.typicode.com/posts" 
});

export default function App() {
  const [post, setPost] = React.useState(null);

  React.useEffect(() =&gt; {
    client.get("/1").then((response) =&gt; {
      setPost(response.data);
    });
  }, []);

  function deletePost() {
    client
      .delete("/1")
      .then(() =&gt; {
        alert("Post deleted!");
        setPost(null)
      });
  }

  if (!post) return "No post!"

  return (
    &lt;div&gt;
      &lt;h1&gt;{post.title}&lt;/h1&gt;
      &lt;p&gt;{post.body}&lt;/p&gt;
      &lt;button onClick={deletePost}&gt;Delete Post&lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre><p>La única propiedad en el objeto de configuración anterior es <code>baseURL</code>, a la que pasa el endpoint.</p><p>La función <code>.create()</code> devuelve una instancia recién creada, que en este caso se llama <code>client</code>.</p><p>Luego, en el futuro, puedes usar todos los mismos métodos que usaste antes, pero ya no tienes que incluir la <code>baseURL</code> como el primer argumento. Solo tiene que hacer referencia a la ruta específica que desea, por ejemplo, <code>/</code>, <code>/1</code>, etc.</p><h2 id="c-mo-usar-la-sintaxis-async-await-con-axios"><strong>Cómo usar la sintaxis Async-Await con Axios</strong></h2><p>Un gran beneficio de usar promesas en JavaScript (incluidas las aplicaciones React) es la sintaxis async-await.</p><p>Async-await te permite escribir un código mucho más limpio sin los callbacks <code>then</code> y <code>catch</code>. Además, el código con async-await se parece mucho al código síncrono y es más fácil de entender.</p><p>Pero, ¿cómo se usa la sintaxis async-await con Axios?</p><p>En el siguiente ejemplo, se recuperan las publicaciones y todavía hay un botón para eliminar esa publicación:</p><pre><code class="language-js">import axios from "axios";
import React from "react";

const client = axios.create({
  baseURL: "https://jsonplaceholder.typicode.com/posts" 
});

export default function App() {
  const [post, setPost] = React.useState(null);

  React.useEffect(() =&gt; {
    async function getPost() {
      const response = await client.get("/1");
      setPost(response.data);
    }
    getPost();
  }, []);

  async function deletePost() {
    await client.delete("/1");
    alert("Post deleted!");
    setPost(null);
  }

  if (!post) return "No post!"

  return (
    &lt;div&gt;
      &lt;h1&gt;{post.title}&lt;/h1&gt;
      &lt;p&gt;{post.body}&lt;/p&gt;
      &lt;button onClick={deletePost}&gt;Delete Post&lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre><p>Sin embargo, en <code>useEffect</code>, hay una función <code>async</code> llamada <code>getPost</code>.</p><p>Hacerlo <code>async</code> te permite usar la palabra clave <code>await</code> para resolver la solicitud GET y establecer esos datos en estado en la siguiente línea sin la devolución de llamada <code>.then()</code>.</p><p>Ten en cuenta que la función <code>getPost</code> se llama inmediatamente después de su creación.</p><p>Además, la función <code>deletePost</code> ahora es <code>async</code>, lo cual es un requisito para usar la palabra clave &nbsp; que resuelve la promesa que devuelve (todos los métodos de Axios devuelven una promesa para resolver).</p><p>Después de usar la palabra clave <code>await</code> con la solicitud DELETE, se alerta al usuario de que la publicación se eliminó y la publicación se establece en <code>null</code>.</p><p>Como puedes ver, async-await limpia mucho el código y puedes usarlo con Axios muy fácilmente.</p><h2 id="c-mo-crear-un-hook-useaxios-personalizado"><strong>Cómo crear un hook <strong><code>useAxios</code></strong> personalizado</strong></h2><p>Async-await es una excelente manera de simplificar su código, pero puede llevar esto un paso más allá.</p><p>En lugar de usar <code>useEffect</code> para obtener datos cuando se monta el componente, puedes crear su propio hook personalizado con Axios para realizar la misma operación que una función reutilizable.</p><p>Si bien puedes crear este hook personalizado por ti mismo, hay una biblioteca muy buena que te brinda un hook personalizado <code>useAxios</code> llamado use-axios-client.</p><p>Primero, instala el paquete:</p><pre><code>npm install use-axios-client</code></pre><p>Para usar el hook en sí, importa <code>useAxios</code> desde use-axios-client en la parte superior del componente.</p><p>Como ya no necesitas <code>useEffect</code>, puede eliminar la importación de React:</p><pre><code class="language-js">import { useAxios } from "use-axios-client";

export default function App() {
  const { data, error, loading } = useAxios({
    url: "https://jsonplaceholder.typicode.com/posts/1"
  });

  if (loading || !data) return "Loading...";
  if (error) return "Error!";

  return (
    &lt;div&gt;
      &lt;h1&gt;{data.title}&lt;/h1&gt;
      &lt;p&gt;{data.body}&lt;/p&gt;
    &lt;/div&gt;
  ) 
}</code></pre><p>Ahora puedes llamar a <code>useAxios</code> en la parte superior del componente de la aplicación, pasar la URL a la que desea realizar una solicitud y el hook devuelve un objeto con todos los valores que necesita para manejar los diferentes estados: <code>loading</code>, <code>error</code> y <code>data</code> resueltos .</p><p>En el proceso de realizar esta solicitud, el valor de <code>loading</code> será verdadero. Si hay un error, querrás mostrar ese estado de error. De lo contrario, si tiene los datos devueltos, puede mostrarlos en la interfaz de usuario.</p><p>El beneficio de los hooks personalizados como este es que realmente reduce el código y lo simplifica en general.</p><p>Si estás buscando una manera de obtener datos aún más simple con Axios, prueba un gancho de <code>useAxios</code> personalizado como este.</p><h2 id="-qu-sigue"><strong>¿Qué sigue?</strong></h2><p>¡Felicidades! Ahora sabes cómo usar una de las bibliotecas de clientes HTTP más poderosas para potenciar sus aplicaciones React.</p><p> Espero que hayas sacado mucho provecho de esta guía.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Proyecto ReactJS: Crea una Wiki de personajes de Rick y Morty ]]>
                </title>
                <description>
                    <![CDATA[ Artículo original escrito por: Joy Shaheb [https://www.freecodecamp.org/news/author/joy/] Artículo original: ReactJS Project – Build a Rick and Morty Character Wiki [https://www.freecodecamp.org/news/react-js-project-build-a-rick-and-morty-character-wiki/] Traducido y adaptado por: Juan C. Guaña [/espanol/news/author/juancguana/] Hoy vamos a practicar nuestras habilidades de React JS construyendo una Wiki de personajes de Rick and Morty. Esto es lo que ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/proyecto-reactjs-crea-un-wiki-de-personajes-de-rick-y-morty/</link>
                <guid isPermaLink="false">61b1693cfca5a008c7b2ee48</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan C. Guaña ]]>
                </dc:creator>
                <pubDate>Fri, 04 Feb 2022 04:38:51 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/12/FCC.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong>Artículo original escrito por</strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong>:</strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong> </strong></strong><a href="https://www.freecodecamp.org/news/author/joy/">Joy Shaheb</a><br><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong>Artículo original</strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong>:</strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong> </strong><a href="https://www.freecodecamp.org/news/react-js-project-build-a-rick-and-morty-character-wiki/">ReactJS Project – Build a Rick and Morty Character Wiki</a><br><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong>Traducido y adaptado por</strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong></strong>:</strong></strong></strong></strong></strong></strong></strong></strong> </strong></strong></strong></strong></strong></strong></strong></strong><a href="https://www.freecodecamp.org/espanol/news/author/juancguana/">Juan C. Guaña</a></p><p>Hoy vamos a practicar nuestras habilidades de React JS construyendo una Wiki de personajes de Rick and Morty.</p><p>Esto es lo que construiremos hoy:</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/cufjzu9x8i7iuxmttzyf.png" class="kg-image" alt="Image description" width="1535" height="921" loading="lazy"></figure><p>Aquí hay una [demostración en vivo del proyecto] ?‌<br><a href="https://react-projects-psi.vercel.app/">https://react-projects-psi.vercel.app/</a>.</p><p>Y <a href="https://github.com/JoyShaheb/React-Projects/tree/main/Level-1/rick-morty-wiki">aquí está el repositorio de GitHub.</a></p><p>Los temas que cubriremos mientras construimos este proyecto son:</p><ul><li>React Hooks (useState, useEffect)</li><li>React Components</li><li>Fetch API</li><li>Bootstrap - para estilos</li><li>Paginación </li><li>Barra de búsqueda </li><li>Filtrado de datos </li><li>Enrutamiento dinámico</li></ul><h2 id="tambi-n-puedes-ver-este-tutorial-en-youtube-si-lo-deseas-"><strong>También puedes ver este tutorial en YouTube si lo deseas:</strong></h2><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.17977528089888%;" class="fluid-width-video-wrapper">
            <iframe width="356" height="200" src="https://www.youtube.com/embed/35QCQnohLg8?start=15090&amp;feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" name="fitvid0"></iframe>
          </div>
        </div>
      </figure><h2 id="caracter-sticas-del-proyecto"><strong>Características del proyecto</strong></h2><p>Veamos una demostración de todas las funciones que crearemos durante todo el transcurso de este artículo.</p><p>Este proyecto está lleno de características interesantes para que pueda aprovechar al máximo este tutorial y ser realmente bueno escribiendo código ReactJS.</p><h3 id="barra-de-b-squeda"><strong>Barra de búsqueda</strong></h3><p>Construiremos esta barra de búsqueda genial para que podamos buscar a nuestros personajes favoritos.</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/oamlwwlpdi12mxyo5fyo.gif" class="kg-image" alt="Image description" width="1484" height="928" loading="lazy"></figure><h3 id="paginaci-n"><strong>Paginación</strong></h3><p>En total hay más de 800 caracteres. Para mostrar y administrar todos estos caracteres, implementaremos un sistema de paginación donde cada página mostrará 20 caracteres.</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h1xv509vqui8s326dr4u.gif" class="kg-image" alt="Image description" width="1112" height="868" loading="lazy"></figure><h3 id="filtros"><strong>Filtros</strong></h3><p>Hay muchas etiquetas presentes en la API. Utilizándolas, podemos filtrar nuestros datos y buscar exactamente lo que necesitamos. Aquí está la demostración:</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nxcx8oqqmgw6nqns0gdz.gif" class="kg-image" alt="Image description" width="1112" height="796" loading="lazy"></figure><h3 id="enrutamiento"><strong>Enrutamiento</strong></h3><p>Implementaremos este componente para cambiar nuestras páginas y crear una barra de navegación. Usaremos la libreria llamada <code>react-router-dom</code> para hacer esto.</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i5in52wka4jccwdrol9l.gif" class="kg-image" alt="Image description" width="1112" height="796" loading="lazy"></figure><h3 id="enrutamiento-din-mico"><strong>Enrutamiento dinámico</strong></h3><p>Usando <code>react-router-dom</code>, también agregaremos enrutamiento dinámico para que podamos aprender más sobre un personaje cuando hagamos clic en él.</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wx9c3gld1hvnn7nz3sda.gif" class="kg-image" alt="Image description" width="1308" height="896" loading="lazy"></figure><h1 id="tabla-de-contenido"><strong>Tabla de contenido</strong></h1><ul><li>Configuración</li><li>Estructura de carpetas</li><li>Obtención de datos</li><li>Tarjetas de personaje</li><li>Barra de búsqueda</li><li>Paginación con React</li><li>Filtros</li><li>Enrutamiento con React</li><li>Episodios</li><li>Ubicación</li><li>Páginas dinámicas</li></ul><h1 id="configuraci-n"><strong>Configuración</strong></h1><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dvqlz2dbwxw8hfw05s2w.png" class="kg-image" alt="Image description" width="800" height="400" loading="lazy"></figure><p>Antes de comenzar el proyecto, sigue estos pasos para configurarlo:</p><ul><li>Crea una carpeta llamada 'react-wiki'</li><li>Abre esa carpeta en VS code</li><li>Abre tu terminal y ejecuta estos comandos uno por uno: ?</li></ul><pre><code class="language-js">npx create-react-app .

npm install bootstrap

npm install @popperjs/core --save

npm install sass

npm install react-router-dom

npm install react-paginate --save

npm start
</code></pre><p>Para facilitar su experiencia de desarrollo, descarga estas extensiones de &nbsp;VSCode:</p><ul><li>ES7 React/Redux/GraphQL/React-Native snippets</li><li>ESLint</li></ul><h1 id="estructura-de-carpeta"><strong>Estructura de carpeta</strong></h1><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/q4m7qo4j58o8fge72dgx.png" class="kg-image" alt="Image description" width="800" height="400" loading="lazy"></figure><p>Dividiremos todo nuestro proyecto en 5 componentes:</p><ul><li>Card</li><li>Pagination</li><li>Search</li><li>Filter</li><li>Navbar</li></ul><p>Crea una carpeta llamada 'components' dentro de su carpeta 'src' y crea 5 carpetas como esta: ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/m58kt2r2cu7u5nfe7h9t.png" class="kg-image" alt="Image description" width="812" height="420" loading="lazy"></figure><p>Y luego, crea estos archivos de acuerdo con los nombres de nuestros componentes. ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/gziuy17t2zlub3m30nro.png" class="kg-image" alt="Image description" width="732" height="525" loading="lazy"></figure><h3 id="app-js"><strong>App.js</strong></h3><p>Algunos otros cambios que necesitas hacer:</p><ul><li>Elimina todo del archivo <code>App.css</code></li><li>Importa los React hooks y Bootstrap en la parte superior en <code>App.js</code></li></ul><pre><code class="language-js">import "bootstrap/dist/css/bootstrap.min.css";
import "bootstrap/dist/js/bootstrap";
import React, { useState, useEffect } from "react";
</code></pre><p>A continuación, importa todos sus módulos desde componentes:</p><pre><code class="language-js">import Search from "./components/Search/Search";
import Card from "./components/Card/Card";
import Pagination from "./components/Pagination/Pagination";
import Filter from "./components/Filter/Filter";
import Navbar from "./components/Navbar/Navbar";
</code></pre><p>Dentro del <code>return statement</code>, elimina todo y agrega este código: ?</p><pre><code class="language-js">&lt;div className="App"&gt;
  &lt;h1 className="text-center mb-3"&gt;Characters&lt;/h1&gt;
  &lt;div className="container"&gt;
  &lt;div className="row"&gt;
    Filter component will be placed here
    &lt;div className="col-lg-8 col-12"&gt;
      &lt;div className="row"&gt;
        Card component will be placed here
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</code></pre><h3 id="index-css"><strong>index.css</strong></h3><p>Agrega estos estilos predeterminados: ?</p><pre><code class="language-css">@import url('https://fonts.googleapis.com/css2?family=Ubuntu:wght@300;400;500;700&amp;display=swap');

body {
  margin: 0;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
}

.ubuntu {
  font-family: "Ubuntu" !important;
}

code {
  font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
    monospace;
}
</code></pre><p>Este es el resultado hasta ahora:<br></p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/hiwhca06v6q4f6nvy6fs.png" class="kg-image" alt="Image description" width="1491" height="232" loading="lazy"></figure><p>¡Felicidades! Hemos terminado con el proceso de configuración. Así que ahora comencemos a codificar.</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zaff3h3an5botfzfdjxa.png" class="kg-image" alt="Image description" width="800" height="400" loading="lazy"></figure><h1 id="c-mo-obtener-datos-de-la-api"><strong>Cómo obtener datos de la API</strong></h1><p>Para obtener datos de nuestra API, usaremos <a href="https://rickandmortyapi.com/">la API de personajes de Rick and Morty</a>. Tendremos que agregar algunas cosas.</p><h3 id="app-js-"><strong>App.js ?</strong></h3><pre><code class="language-js"> let api = `https://rickandmortyapi.com/api/character/?page=1`
</code></pre><p><strong>Nota:</strong> no uses comillas o comillas dobles alrededor de la URL, usa comillas invertidas en su lugar. ☝</p><p>Para obtener datos de esta API, usaremos nuestro hook <code>useEffects</code> de esta manera: ?</p><pre><code class="language-js">  useEffect(() =&gt; { }, [api]);
</code></pre><p>Estamos escribiendo el hook <code>useEffect</code> y poniendo el observador en <code>api</code>. Esto significa que, en caso de que cambie la variable <code>api</code>, queremos recargar datos nuevos. <br><br>Continuemos. ?</p><pre><code class="language-js">useEffect(() =&gt; {
  (async function () {
    let data = await fetch(api).then((res) =&gt; res.json());
    console.log(data);
  })();
}, [api]);
</code></pre><p>Estamos usando una función asíncrona para obtener nuestros datos sin procesar y luego los convertimos al formato JSON. Revisemos la consola para ver qué tenemos hasta ahora: ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/pbtaztnmfa3e9t9hi8js.png" class="kg-image" alt="Image description" width="1072" height="655" loading="lazy"></figure><p>¿Quieres probarlo tú mismo? Cambia el número de página a 2 dentro de la API y encontrarás nuevos datos en tu consola: ?</p><pre><code class="language-js">let api = `https://rickandmortyapi.com/api/character/?page=1`
</code></pre><p>En lugar de almacenar los datos en la consola, usemos el hook <code>useState</code>. Esto almacenará los datos en una variable, y tendremos una clave de función para cambiar los datos de la variable cada vez que el hook useEffect obtenga nuevos datos. ?</p><pre><code class="language-js">let [fetchedData, updateFetchedData] = useState([]);
let { info, results } = fetchedData;
</code></pre><p>Además, estamos desestructurando <code>info and result</code> de la variable <code>fetchedData</code> para facilitarnos la vida. ?</p><p>La variable <code>fetchedData</code> almacenará los datos que obtuvimos de la API. Usaremos la función <code>updateFetchedData</code> para cambiar los datos cuando queramos.</p><p>Cambiemos nuestro hook useEffect: ?</p><pre><code class="language-js">useEffect(() =&gt; {
  (async function () {
    let data = await fetch(api).then((res) =&gt; res.json());
    updateFetchedData(data);
  })();
}, [api]);
</code></pre><h1 id="c-mo-hacer-las-tarjetas-de-personajes"><strong>Cómo hacer las tarjetas de personajes</strong></h1><p>Comencemos a construir nuestras tarjetas de personajes.?</p><p>En primer lugar, importa el componente card reemplazando el texto escrito <code>Card component will be placed here</code>. Luego, pasa los datos obtenidos de nuestro componente <code>App.js</code> a nuestro <code>componente Card</code> de esta manera:?</p><pre><code class="language-js">&lt;Card results={results} /&gt;
</code></pre><h3 id="card-js"><strong>Card.js</strong></h3><p>Ahora, primero desestructura los datos que obtuvimos de nuestro componente App.js.?</p><pre><code class="language-js">const Card = ({ results }) =&gt; {}
</code></pre><p>Luego crea una variable llamada <code>display</code>. Esto mantendrá todas nuestras tarjetas. Junto con esto, crearemos una declaración <code>if</code> <code>else</code> para verificar si los datos que obtuvimos de nuestra API están vacíos o no.?</p><pre><code class="language-js">const Card = ({ results }) =&gt; {
  let display;

  if (results) {}
  else{
    display = "No Characters Found :/";
  }

  return &lt;&gt;{display}&lt;/&gt;;
}
</code></pre><p>Ahora, vamos a asignar nuestros <code>results</code> a nuestro componente card de manera que creará tarjetas para nosotros automáticamente. Pero primero, debemos desestructurar los datos que obtuvimos de nuestra API.?</p><pre><code class="language-js">if (results) {
  display = results.map((x) =&gt; {
  let { id, image, name, status, location } = x;

    return (
      &lt;div
        key={id}
        className="col-lg-4 col-md-6 col-sm-6 col-12 mb-4 position-relative text-dark"
      &gt;
      &lt;/div&gt;
  );
});
}
</code></pre><p>Crea un archivo llamado <code>Card.module.scss</code> y agrega este código: ?</p><pre><code class="language-scss">$radius: 10px;
.card {
  border: 2px solid #0b5ed7;
  border-radius: $radius;
}
.content {
  padding: 10px;
}
.img {
  border-radius: $radius $radius 0 0;
}
.badge {
  top: 10px; right: 20px;
  font-size: 17px;
}
</code></pre><p>Además, impórtalo dentro del componente <code>Card.js</code> : ?</p><pre><code class="language-js">import styles from "./Card.module.scss";
</code></pre><p>Ahora es el momento de crear nuestra plantilla de tarjeta y colocar los datos en sus respectivos lugares.?</p><pre><code class="language-js">&lt;div
  className={`${styles.card} d-flex flex-column justify-content-center`}
&gt;
  &lt;img className={`${styles.img} img-fluid`} src={image} alt="" /&gt;
  &lt;div className={`${styles.content}`}&gt;
    &lt;div className="fs-5 fw-bold mb-4"&gt;{name}&lt;/div&gt;
    &lt;div className=""&gt;
      &lt;div className="fs-6 fw-normal"&gt;Last Location&lt;/div&gt;
      &lt;div className="fs-5"&gt;{location.name}&lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</code></pre><p>Los resultados hasta ahora se ven así: ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/50oqyl113kg096fcj0wl.png" class="kg-image" alt="Image description" width="1582" height="912" loading="lazy"></figure><p>Por último, usaremos este código ? para que los usuarios sepan si el personaje está vivo, muerto o desconocido:</p><pre><code class="language-js">{
(() =&gt; {
  if (status === "Dead") {
    return (
      &lt;div className={`${styles.badge} position-absolute badge bg-danger`}&gt;
        {status}
      &lt;/div&gt;
    );
  } else if (status === "Alive") {
    return (
      &lt;div className={`${styles.badge} position-absolute badge bg-success`}&gt;
        {status}
      &lt;/div&gt;
    );
  } else {
    return (
      &lt;div
        className={`${styles.badge} position-absolute badge bg-secondary`}
      &gt;
        {status}
      &lt;/div&gt;
    );
  }
})()}
</code></pre><p>Los resultados hasta ahora: ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4hyl5uugz5h35dsve7wv.png" class="kg-image" alt="Image description" width="1510" height="926" loading="lazy"></figure><h1 id="c-mo-construir-la-barra-de-b-squeda"><strong>Cómo construir la barra de búsqueda</strong></h1><p>Aquí hay un video de demostración de nuestro componente de barra de búsqueda: ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/44tw3yyly0d3hiikhrpo.gif" class="kg-image" alt="Image description" width="1112" height="888" loading="lazy"></figure><p>Ahora, construyamos nuestra barra de búsqueda de personajes. Pero primero, necesitamos crear dos hooks <code>useState</code> para mantener nuestras <code>palabras clave de búsqueda</code> y el <code>número de página actual</code>. ?</p><h3 id="app-js-1"><strong>App.js</strong></h3><pre><code class="language-js">let [pageNumber, updatePageNumber] = useState(1);
let [search, setSearch] = useState("");
</code></pre><p>Luego, necesitamos actualizar nuestra API con variables. Esto significa que siempre que nuestra API cambie, nuestro hook useEffect obtendrá nuevos datos de nuestra base de datos. ?</p><pre><code class="language-js">let api = `https://rickandmortyapi.com/api/character/?page=${pageNumber}&amp;name=${search}`;
</code></pre><p>Ahora, vamos a importar nuestro componente de barra de búsqueda dentro de la declaración de devolución. Y junto con eso, vamos a pasar nuestras variables de estado recién creadas dentro de ese componente. ?</p><pre><code class="language-js">  &lt;h1 className="text-center mb-3"&gt;Characters&lt;/h1&gt;
  &lt;Search setSearch={setSearch} updatePageNumber={updatePageNumber} /&gt;
</code></pre><p>Crea un archivo llamado <code>Search.module.scss</code> para contener los estilos de un módulo específico. Luego, haz estos ajustes: ?</p><h3 id="search-module-scss"><strong>Search.module.scss</strong></h3><pre><code class="language-scss">.input {
  width: 40%; border-radius: 8px;
  border: 2px solid #0b5ed7;
  box-shadow: 1px 3px 9px rgba($color: #000000, $alpha: 0.25);
  padding: 10px 15px;
  &amp;:focus { outline: none; }
}
.btn {
  box-shadow: 1px 3px 9px rgba($color: #000000, $alpha: 0.25);
}
@media (max-width: 576px) {
  .input { width: 80%; }
}
</code></pre><h3 id="search-js"><strong>Search.js</strong></h3><p>En primer lugar, necesitamos desestructurar nuestros accesorios. Luego, crearemos una función llamada <code>searchBtn</code> para evitar el comportamiento predeterminado de nuestra aplicación, de esta manera: ?</p><pre><code class="language-js">import React from "react";
import styles from "./Search.module.scss";

const Search = ({ setSearch, updatePageNumber }) =&gt; {
  let searchBtn = (e) =&gt; {
    e.preventDefault();
  };
};
</code></pre><p>Luego, escribamos dentro de nuestra declaración de devolución. En primer lugar, escribamos la etiqueta de formulario para contener nuestras etiquetas de entrada y botón. ?</p><pre><code class="language-js">return (
  &lt;form
    className={`${styles.search} d-flex flex-sm-row flex-column align-items-center justify-content-center gap-4 mb-5`}
  &gt;
  &lt;/form&gt;
);
</code></pre><p>Luego, creamos el botón y las etiquetas de entrada dentro de nuestra etiqueta de formulario. ?</p><pre><code class="language-js">&lt;input
  onChange={(e) =&gt; {
    updatePageNumber(1);
    setSearch(e.target.value);
  }}
  placeholder="Search for characters"
  className={styles.input}
  type="text"
/&gt;
&lt;button
  onClick={searchBtn}
  className={`${styles.btn} btn btn-primary fs-5`}
&gt;
  Search
&lt;/button&gt;
</code></pre><p>Los resultados hasta ahora: ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/44tw3yyly0d3hiikhrpo.gif" class="kg-image" alt="Image description" width="1112" height="888" loading="lazy"></figure><h1 id="c-mo-configurar-la-paginaci-n-con-react-paginate"><strong>Cómo configurar la paginación con React-paginate</strong></h1><p>Aquí hay una demostración de nuestro componente React-paginate: ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h1xv509vqui8s326dr4u.gif" class="kg-image" alt="Image description" width="1112" height="868" loading="lazy"></figure><p>Vamos a usar <a href="https://www.npmjs.com/package/react-paginate">este paquete</a> para paginar nuestros datos. Entonces, importémoslo en la parte inferior: ?</p><h3 id="app-js-2"><strong>App.js</strong></h3><pre><code class="language-js">&lt;Pagination
  info={info}
  pageNumber={pageNumber}
  updatePageNumber={updatePageNumber}
/&gt;
</code></pre><h3 id="pagination-js"><strong>Pagination.js</strong></h3><p>Aquí, vamos a desestructurar nuestras propiedades y luego escribiremos en algunos estilos JSX: ?</p><pre><code class="language-js">import React, { useState, useEffect } from "react";
import ReactPaginate from "react-paginate";

const Pagination = ({ pageNumber, info, updatePageNumber }) =&gt; {}
</code></pre><p>Dentro de la declaración de devolución, escribimos los estilos en JSX así: ?</p><pre><code class="language-js">return (
&lt;&gt;
&lt;style jsx&gt;
{`
  a {
    color: white; text-decoration: none;
  }
  @media (max-width: 768px) {
    .pagination {font-size: 12px}

    .next,
    .prev {display: none}
  }
  @media (max-width: 768px) {
    .pagination {font-size: 14px}
  }
`}
&lt;/style&gt;
&lt;/&gt;
);
</code></pre><p>Ahora, crea esta función para manejar la función de cambio de página: ?<br></p><pre><code class="language-js">let pageChange = (data) =&gt; {
  updatePageNumber(data.selected + 1);
};
</code></pre><p>Para que nuestro componente de paginación sea adapte al tamaño de la pantalla, necesitamos escribir este pequeño componente:</p><pre><code class="language-js">const [width, setWidth] = useState(window.innerWidth);
const updateDimensions = () =&gt; {
  setWidth(window.innerWidth);
};
useEffect(() =&gt; {
  window.addEventListener("resize", updateDimensions);
  return () =&gt; window.removeEventListener("resize", updateDimensions);
}, []);
</code></pre><p>Muy bien a todos, excelente! Ahora vamos a usar el paquete react-paginate.</p><p>Primero, diseñemos todo usando las propiedades integradas de react-paginate para estilizar los elementos básicos:? </p><pre><code class="language-js">&lt;ReactPaginate
  className="pagination justify-content-center my-4 gap-4"
  nextLabel="Next"
  previousLabel="Prev"
  previousClassName="btn btn-primary fs-5 prev"
  nextClassName="btn btn-primary fs-5 next"
  activeClassName="active"
  pageClassName="page-item"
  pageLinkClassName="page-link"
/&gt;
</code></pre><p>Aquí está lo más importante: vamos a agregar las funcionalidades a nuestro componente para que funcione correctamente. ?</p><pre><code class="language-js">&lt;ReactPaginate
  forcePage={pageNumber === 1 ? 0 : pageNumber - 1}
  marginPagesDisplayed={width &lt; 576 ? 1 : 2}
  pageRangeDisplayed={width &lt; 576 ? 1 : 2}
  pageCount={info?.pages}
  onPageChange={pageChange}
  //.... other props here
/&gt;
</code></pre><p>Los resultados hasta ahora: ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h1xv509vqui8s326dr4u.gif" class="kg-image" alt="Image description" width="1112" height="868" loading="lazy"></figure><h1 id="c-mo-hacer-el-componente-de-filtros"><strong>Cómo hacer el componente de filtros</strong></h1><p>Aquí hay una demostración de nuestro componente de filtros:?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/nxcx8oqqmgw6nqns0gdz.gif" class="kg-image" alt="Image description" width="1112" height="796" loading="lazy"></figure><p>Lo primero que debemos hacer es crear una estructura de carpetas para contener todos los pequeños componentes que vamos a usar. Crea estos componentes dentro de la carpeta <code>Filter</code>:?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1f1mna2c00acmoer45ce.png" class="kg-image" alt="Image description" width="697" height="341" loading="lazy"></figure><h3 id="app-js-3"><strong>App.js</strong></h3><p>Ahora, crea estos useState hooks para almacenar nuestro estado, género y especie.</p><pre><code class="language-js">let [status, updateStatus] = useState("");
let [gender, updateGender] = useState("");
let [species, updateSpecies] = useState("");
</code></pre><p>Además, necesitamos modificar nuestra variable <code>api</code> de acuerdo con nuestras variables de useState hook. ?</p><pre><code class="language-js">  let api = `https://rickandmortyapi.com/api/character/?page=${pageNumber}&amp;name=${search}&amp;status=${status}&amp;gender=${gender}&amp;species=${species}`;
</code></pre><p>Ahora, importaremos nuestro componente &nbsp;<code>filter</code> dentro de nuestra aplicación, donde se colocará aquí su componente de filtro escrito. Además, pasa todas estas propiedades &nbsp;requeridas: ?</p><pre><code class="language-js">&lt;Filter
  pageNumber={pageNumber}
  status={status}
  updateStatus={updateStatus}
  updateGender={updateGender}
  updateSpecies={updateSpecies}
  updatePageNumber={updatePageNumber}
/&gt;
</code></pre><h3 id="filter-js"><strong>Filter.js</strong></h3><p>Hagamos estos cambios en nuestro componente Filtro para que podamos lograr los resultados deseados. Primero, importa todos los componentes de nuestra categoría de esta manera:?</p><pre><code class="language-js">import React from "react";
import Gender from "./category/Gender";
import Species from "./category/Species";
import Status from "./category/Status";
</code></pre><p>Luego, desestructura las propiedades pasadas ​​y coloca un <code>accordion</code> que incluya un <code>clear button</code>:</p><pre><code class="language-js">const Filter = ({
  pageNumber, updatePageNumber,
  updateStatus, updateGender,
  updateSpecies,
}) =&gt; {

return (
&lt;div className="col-lg-3 col-12 mb-5"&gt;
  &lt;div className="text-center fw-bold fs-4 mb-2"&gt;Filters&lt;/div&gt;
  &lt;div
    style={{ cursor: "pointer" }} onClick={clear}
    className="text-primary text-decoration-underline text-center mb-3"
  &gt; Clear Filters &lt;/div&gt;
  &lt;div className="accordion" id="accordionExample"&gt;
    {/* Category components will be placed here */}
  &lt;/div&gt;
&lt;/div&gt;
);
};

</code></pre><p>Realiza esta función para que podamos borrar nuestros filtros y actualizar la página:?</p><pre><code class="language-js">let clear = () =&gt; {
  updateStatus("");
  updateGender("");
  updateSpecies("");
  updatePageNumber(1);
  window.location.reload(false);
};
</code></pre><p>Los resultados hasta ahora se ven así ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/jcnncgfpnjqkaow9201j.png" class="kg-image" alt="Image description" width="460" height="282" loading="lazy"></figure><h3 id="filterbtn-js"><strong>FilterBTN.js</strong></h3><p>Primero, creemos estos botones de filtro. También desestructuraremos las propiedades necesarias. ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dmas54wdnue9d7rfcreg.png" class="kg-image" alt="Image description" width="542" height="506" loading="lazy"></figure><pre><code class="language-js">const FilterBTN = ({ input, task, updatePageNumber, index, name }) =&gt; {
return (
&lt;div&gt;
  &lt;style jsx&gt;
    {`
      .x:checked + label {
        background-color: #0b5ed7;
        color: white }
      input[type="radio"] { display: none; }
    `}
  &lt;/style&gt;
&lt;/div&gt;
);
};
</code></pre><p>Ahora, colocamos el componente de entrada principal con etiquetas debajo del <code>style jsx</code>: ?</p><pre><code class="language-js">&lt;div className="form-check"&gt;
  &lt;input
    className="form-check-input x" type="radio"
    name={name} id={`${name}-${index}`}
  /&gt;
  &lt;label
    onClick={(x) =&gt; {
      task(input); updatePageNumber(1);
    }}
    className="btn btn-outline-primary"
    for={`${name}-${index}`}
  &gt; {input} &lt;/label&gt;
&lt;/div&gt;
</code></pre><h3 id="status-js"><strong>Status.js</strong></h3><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dmas54wdnue9d7rfcreg.png" class="kg-image" alt="Image description" width="542" height="506" loading="lazy"></figure><p>Escribe este código de inicio dentro de Status.js:</p><pre><code class="language-js">import FilterBTN from "../FilterBTN";

const Status = ({ updateStatus, updatePageNumber }) =&gt; {
  let status = ["Alive", "Dead", "Unknown"];
  return (
    &lt;div className="accordion-item"&gt;
      &lt;h2 className="accordion-header" id="headingOne"&gt;
        &lt;button
          className="accordion-button" type="button"
          data-bs-toggle="collapse" data-bs-target="#collapseOne"
          aria-expanded="true" aria-controls="collapseOne"
        &gt; Status &lt;/button&gt;
      &lt;/h2&gt;
    &lt;/div&gt;
  );
};
</code></pre><p>Luego, crea los botones de estado mapeando nuestro arreglos de datos. ?</p><p>Debajo de la etiqueta <code>h2</code> final, colócalos dentro ?, lo que nos ayudará a mapear automáticamente los datos y crear nuestros botones de estado:</p><pre><code class="language-js">&lt;div
  id="collapseOne" className="accordion-collapse collapse show"
  aria-labelledby="headingOne" data-bs-parent="#accordionExample"
&gt;
&lt;div className="accordion-body d-flex flex-wrap gap-3"&gt;
  {status.map((item, index) =&gt; (
    &lt;FilterBTN
      key={index}
      index={index}
      name="status"
      task={updateStatus}
      updatePageNumber={updatePageNumber}
      input={item}
    /&gt;
  ))}
&lt;/div&gt;
&lt;/div&gt;
</code></pre><h4 id="hora-de-probar-en-filter-js"><strong>Hora de probar en Filter.js</strong></h4><p>Escribe estas líneas dentro del Filter.js para comprobar si el componente funciona o no: ?</p><pre><code class="language-js">&lt;Status
  updatePageNumber={updatePageNumber}
  updateStatus={updateStatus}
/&gt;
</code></pre><p>Los resultados hasta ahora: ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kxcq2s8q8ntfe6dh36vc.gif" class="kg-image" alt="Image description" width="1112" height="796" loading="lazy"></figure><h3 id="species-js"><strong>Species.js</strong></h3><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/mmvw4v4tqh6gx2lupoju.png" class="kg-image" alt="Image description" width="682" height="667" loading="lazy"></figure><p>Escribe estos códigos de inicio dentro de Species.js:</p><pre><code class="language-js">import FilterBTN from "../FilterBTN";

const Species = ({ updateSpecies, updatePageNumber }) =&gt; {
return (
&lt;div className="accordion-item "&gt;
  &lt;h2 className="accordion-header" id="headingTwo"&gt;
    &lt;button
      className="accordion-button collapsed" type="button"
      data-bs-toggle="collapse" data-bs-target="#collapseTwo"
      aria-expanded="false" aria-controls="collapseTwo"
    &gt; Species &lt;/button&gt;
  &lt;/h2&gt;
&lt;/div&gt;
)}
</code></pre><p>Ahora, crea un arreglo para contener todos nuestros posibles datos de especies: ?</p><pre><code class="language-js">  let species = [
    "Human", "Alien", "Humanoid",
    "Poopybutthole", "Mythological", "Unknown",
    "Animal", "Disease","Robot","Cronenberg","Planet",
  ];
</code></pre><p>Y luego, creamos los botones Species mapeando nuestro arreglo de datos de esta manera: ?</p><pre><code class="language-js">&lt;div
    id="collapseTwo" className="accordion-collapse collapse"
    aria-labelledby="headingTwo"
    data-bs-parent="#accordionExample"
  &gt;
  &lt;div className="accordion-body d-flex flex-wrap gap-3"&gt;
    {species.map((item, index) =&gt; {
      return (
        &lt;FilterBTN
          name="species" index={index} key={index}
          updatePageNumber={updatePageNumber}
          task={updateSpecies} input={item}
        /&gt;
      );
    })}
  &lt;/div&gt;
&lt;/div&gt;
</code></pre><h4 id="hora-de-probar-en-filter-js-1"><strong>Hora de probar en Filter.js</strong></h4><p>Escriba estas líneas dentro de Filter.js para verificar si el componente funciona o no: ?</p><pre><code class="language-js">&lt;Species
  updatePageNumber={updatePageNumber}
  updateSpecies={updateSpecies}
/&gt;
</code></pre><p>Los resultados hasta ahora: ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/aav8duudtdkwxznfayn0.gif" class="kg-image" alt="Image description" width="1112" height="796" loading="lazy"></figure><h3 id="gender-js"><strong>Gender.js</strong></h3><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/45yw5m81hr3utyydwfms.png" class="kg-image" alt="Image description" width="618" height="532" loading="lazy"></figure><p>Escribe este código de inicio:?</p><pre><code class="language-js">import FilterBTN from "../FilterBTN";

const Gender = ({ updateGender, updatePageNumber }) =&gt; {
let genders = ["female", "male", "genderless", "unknown"];
return (
  &lt;div className="accordion-item"&gt;
    &lt;h2 className="accordion-header" id="headingThree"&gt;
      &lt;button
        className="accordion-button collapsed" type="button"
        data-bs-toggle="collapse" data-bs-target="#collapseThree"
        aria-expanded="false" aria-controls="collapseThree"
      &gt; Gender &lt;/button&gt;
    &lt;/h2&gt;
  &lt;/div&gt;
);
};
</code></pre><p>Debajo de la etiqueta <code>h2</code> final, coloca este código dentro? que nos ayudará a mapear automáticamente los datos y crear nuestros botones de género:</p><pre><code class="language-js">&lt;div id="collapseThree" className="accordion-collapse collapse"
  aria-labelledby="headingThree" data-bs-parent="#accordionExample"
&gt;
&lt;div className="accordion-body d-flex flex-wrap gap-3"&gt;
  {genders.map((items, index) =&gt; {
    return (
      &lt;FilterBTN
        name="gender" index={index} key={index}
        updatePageNumber={updatePageNumber}
        task={updateGender} input={items}
      /&gt;
      );
    })}
  &lt;/div&gt;
&lt;/div&gt;
</code></pre><h4 id="hora-de-probar-en-filter-js-2"><strong>Hora de probar en Filter.js</strong></h4><p>Escribe estas líneas dentro de Filter.js para comprobar si el componente funciona o no: ?</p><pre><code class="language-js">&lt;Gender
  updatePageNumber={updatePageNumber}
  updateGender={updateGender}
/&gt;
</code></pre><p>Los resultados hasta ahora: ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/9aklsikf2brx5h7vxxsm.gif" class="kg-image" alt="Image description" width="1112" height="796" loading="lazy"></figure><h1 id="c-mo-configurar-react-router"><strong>Cómo configurar React Router</strong></h1><p>Aquí hay una demostración de nuestro componente de navegación: ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i5in52wka4jccwdrol9l.gif" class="kg-image" alt="Image description" width="1112" height="796" loading="lazy"></figure><p>Comencemos a codificar!</p><p>Primero, crea una carpeta llamada <code>Pages</code> dentro de la carpeta <code>src</code>. Contendrá 2 archivos: <code>Episodes.j</code> y <code>Location.js</code>. Algo como esto:?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/fd0k8mt8s1sq842axwsd.png" class="kg-image" alt="Image description" width="771" height="295" loading="lazy"></figure><h3 id="app-js-4"><strong>App.js</strong></h3><p>Importa su componente de páginas recién creado en <code>App.js</code>: ?</p><pre><code class="language-js">import Episodes from "./Pages/Episodes";
import Location from "./Pages/Location";
</code></pre><p>Para declarar el enrutador y definir todo tipo de rutas de archivos, debemos importar <code>react-router-dom</code> en <code>App.js</code>, incluidos sus componentes principales. ?</p><pre><code class="language-js">import { BrowserRouter as Router, Routes, Route } from "react-router-dom";
</code></pre><p>Ahora, crea un nuevo componente funcional llamado <code>Home</code> dentro del archivo <code>App.js</code>. Luego, corta todo desde el componente <code>App</code> y colóquelo dentro del componente <code>Home</code>: ?</p><pre><code class="language-js">const Home = () =&gt; {
  // Everything you've written so far
}
</code></pre><p>Dentro de la función del componente <code>App</code>, crea un nuevo componente <code>Router</code> y colóquelo dentro del componente <code>Navbar</code>. ?</p><pre><code class="language-js">function App() {
  return (
    &lt;Router&gt;
      &lt;div className="App"&gt;
        &lt;Navbar /&gt;
      &lt;/div&gt;
    &lt;/Router&gt;
  );
}
</code></pre><p>Ahora, necesitamos definir todas nuestras rutas. Recuerda, <code>Routes</code> es una colección de <code>Route</code>. La ruta es la ruta real del archivo.</p><p>Cada ruta requiere 2 cosas: el <code>path</code> al que conducirá la aplicación y el <code>element</code> que se cargará. ?</p><pre><code class="language-js">&lt;Routes&gt;
  &lt;Route path="/" element={&lt;Home /&gt;} /&gt;

  &lt;Route path="/episodes" element={&lt;Episodes /&gt;} /&gt;

  &lt;Route path="/location" element={&lt;Location /&gt;} /&gt;
&lt;/Routes&gt;
</code></pre><h3 id="navbar-js"><strong>Navbar.js</strong></h3><p>¡Hasta ahora todo bien! Ahora, hagamos el componente de la barra de navegación. Primero, importa 2 componentes desde <code>react-router-dom</code>. Luego, escribe esta clase principal de arranque que incluya el nombre de la marca para contener nuestro componente de páginas de la barra de navegación:?</p><pre><code class="language-js">import { NavLink, Link } from "react-router-dom";

const Navbar = () =&gt; {
return (
  &lt;nav className="navbar navbar-expand-lg navbar-light bg-light mb-4"&gt;
    &lt;div className="container"&gt;
      &lt;Link to="/" className="navbar-brand fs-3 ubuntu"&gt;
        Rick &amp; Morty &lt;span className="text-primary"&gt;WiKi&lt;/span&gt;
      &lt;/Link&gt;
      &lt;style jsx&gt;{`
        button[aria-expanded="false"] &gt; .close {
          display: none;
        }
        button[aria-expanded="true"] &gt; .open {
          display: none;
        }
      `}&lt;/style&gt;
    &lt;/div&gt;
  &lt;/nav&gt;
);
};
</code></pre><p>Escribe este código para generar nuestro menú de hamburguesas responsivo:?</p><pre><code class="language-js">&lt;button
  className="navbar-toggler border-0"
  type="button"
  data-bs-toggle="collapse"
  data-bs-target="#navbarNavAltMarkup"
  aria-controls="navbarNavAltMarkup"
  aria-expanded="false"
  aria-label="Toggle navigation"
&gt;
  &lt;span class="fas fa-bars open text-dark"&gt;&lt;/span&gt;
  &lt;span class="fas fa-times close text-dark"&gt;&lt;/span&gt;
&lt;/button&gt;
</code></pre><p>Escribe este código para generar nuestros enlaces de barra de navegación en los que se puede hacer clic. Ten en cuenta que estamos usando el componente de <code>react-router-dom</code> para vincular a la URL del componente de nuestra página: ?</p><pre><code class="language-js">&lt;div
  className="collapse navbar-collapse justify-content-end"
  id="navbarNavAltMarkup"
&gt; &lt;div className="navbar-nav fs-5"&gt;
    &lt;NavLink to="/" className="nav-link"&gt;
      Characters
    &lt;/NavLink&gt;
    &lt;NavLink to="/episodes" className="nav-link"&gt;
      Episode
    &lt;/NavLink&gt;
    &lt;NavLink
      activeClassName="active" className="nav-link"
      to="/location" &gt;Location&lt;/NavLink&gt;
  &lt;/div&gt;
&lt;/div&gt;
</code></pre><h3 id="app-css"><strong>App.css</strong></h3><p>Además, escribe estos estilos si deseas que la barra de navegación se vea bien y que sus usuarios sepan exactamente en qué página se encuentran actualmente: ?</p><pre><code class="language-css">.active {
  color: #0b5ed7 !important;
  font-weight: bold;
  border-bottom: 3px solid #0b5ed7;
}
</code></pre><p>Luego, dentro de <code>Navbar.js</code>, importa los estilos de esta manera: ?</p><pre><code class="language-js">import "../../App.css";
</code></pre><p>El resultado hasta ahora: ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/i5in52wka4jccwdrol9l.gif" class="kg-image" alt="Image description" width="1112" height="796" loading="lazy"></figure><h1 id="episodios"><strong>Episodios</strong></h1><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kby93lasrq6di8md58sg.png" class="kg-image" alt="Image description" width="1293" height="808" loading="lazy"></figure><p>Para crear esta página, necesitamos 2 componentes: el primero es el componente <code>card</code>, que ya está construido, y el segundo es el componente <code>Input Group</code> a través del cual podemos cambiar nuestro número de episodio.</p><h3 id="inputgroup-js"><strong>InputGroup.js</strong></h3><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/d53jsa8tz1e2aab1dk9s.gif" class="kg-image" alt="Image description" width="868" height="772" loading="lazy"></figure><p>Nuestros grupos de entrada solo estarán disponibles en el componente <code>Episodes</code> y <code>Location</code> para que podamos cambiar el número de episodio y la ubicación para buscar personajes. ¡Empecemos! ?</p><p>Dentro de la carpeta <code>category</code> de la carpeta <code>Filter</code>, crea un nuevo archivo llamado <code>InputGroup.js</code> y escriba este código de inicio, incluido el sistema de desestructuración de accesorios: ?</p><pre><code class="language-js">const InputGroup = ({ name, changeID, total }) =&gt; {
return &lt;div className="input-group mb-3"&gt;
  &lt;select
  onChange={(e) =&gt; changeID(e.target.value)}
  className="form-select"
  id={name}
  &gt;&lt;/select&gt;
&lt;/div&gt;
};
</code></pre><p>Luego, creemos nuestra opción de grupo de entrada. Escriba este código dentro de su etiqueta <code>select</code>: ?</p><pre><code class="language-js">&lt;option value="1"&gt;Choose...&lt;/option&gt;
{[...Array(total).keys()].map((x, index) =&gt; {
  return (
    &lt;option value={x + 1}&gt;
      {name} - {x + 1}
    &lt;/option&gt;
  );
})}
</code></pre><h3 id="episodes-js"><strong>Episodes.js</strong></h3><p>Dentro de este archivo, importe estos componentes:?</p><pre><code class="language-js">import React, { useEffect, useState } from "react";
import Card from "../components/Card/Card";
import InputGroup from "../components/Filter/category/InputGroup";
</code></pre><p>Ahora, crea estos estados para que podamos retener y cambiar información crucial para obtener datos de nuestra <code>api</code>:?</p><pre><code class="language-js">const Episodes = () =&gt; {
  let [results, setResults] = React.useState([]);
  let [info, setInfo] = useState([]);
  let { air_date, episode, name } = info;
  let [id, setID] = useState(1);

let api = `https://rickandmortyapi.com/api/episode/${id}`;
}
</code></pre><p>Escriba este código para obtener datos de nuestra API: ?</p><pre><code class="language-js">useEffect(() =&gt; {
  (async function () {
    let data = await fetch(api).then((res) =&gt; res.json());
    setInfo(data);

    let a = await Promise.all(
      data.characters.map((x) =&gt; {
        return fetch(x).then((res) =&gt; res.json());
      })
    );
    setResults(a);
  })();
}, [api]);
</code></pre><p>Ahora, escribamos el código para representar los resultados en nuestra pantalla. Primero, mostremos el nombre del episodio y la fecha de emisión de esta manera: ?</p><pre><code class="language-js">return (
&lt;div className="container"&gt;
  &lt;div className="row mb-3"&gt;
    &lt;h1 className="text-center mb-3"&gt;
      Episode name :{" "}
      &lt;span className="text-primary"&gt;{name === "" ? "Unknown" : name}&lt;/span&gt;
    &lt;/h1&gt;
    &lt;h5 className="text-center"&gt;
      Air Date: {air_date === "" ? "Unknown" : air_date}
    &lt;/h5&gt;
  &lt;/div&gt;
&lt;/div&gt;
);
</code></pre><p>Los resultados hasta ahora se ven así: ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/8rq6yd767in8qi5eu3mt.png" class="kg-image" alt="Image description" width="1465" height="280" loading="lazy"></figure><p>Ahora, mostremos las tarjetas de personajes y los grupos de entrada: ?</p><pre><code class="language-js">&lt;div className="row"&gt;
  &lt;div className="col-lg-3 col-12 mb-4"&gt;
    &lt;h4 className="text-center mb-4"&gt;Pick Episode&lt;/h4&gt;
    &lt;InputGroup name="Episode" changeID={setID} total={51} /&gt;
  &lt;/div&gt;
  &lt;div className="col-lg-8 col-12"&gt;
    &lt;div className="row"&gt;
      &lt;Card results={results} /&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;
</code></pre><p>Los resultados hasta ahora: ?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/kby93lasrq6di8md58sg.png" class="kg-image" alt="Image description" width="1293" height="808" loading="lazy"></figure><h1 id="location"><strong>Location</strong></h1><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4yq78xas7xjcgzgnkp74.gif" class="kg-image" alt="Image description" width="1480" height="896" loading="lazy"></figure><p>Hacer este componente es similar a hacer una página de <code>episodes</code>. Primero, copia todo desde la página de <code>episodes</code> y realiza estos pocos cambios:?</p><pre><code class="language-js">  let [results, setResults] = useState([]);
  let [info, setInfo] = useState([]);
  let { dimension, type, name } = info;
  let [number, setNumber] = useState(1);

  let api = `https://rickandmortyapi.com/api/location/${number}`;
</code></pre><p>Ahora cambie solo una palabra clave en el hook <code>useEffect</code>, de <code>characters</code> a <code>residents</code>, así:?</p><pre><code class="language-js">useEffect(() =&gt; {
      // Other codes are here
      data.residents.map((x) =&gt; {
      })
    // Other codes are here
}, [api]);
</code></pre><p>En la declaración de devolución, realiza estos cambios: ?</p><pre><code class="language-js">return (
&lt;h1 className="text-center mb-3"&gt;
  Location :
  &lt;span className="text-primary"&gt;
    {name === "" ? "Unknown" : name}
  &lt;/span&gt;
&lt;/h1&gt;
&lt;h5 className="text-center"&gt;
  Dimension: {dimension === "" ? "Unknown" : dimension}
&lt;/h5&gt;
&lt;h6 className="text-center"&gt;Type: {type === "" ? "Unknown" : type}&lt;/h6&gt;
);
</code></pre><p>Y finalmente, realiza estos cambios para nuestro componente <code>InputGroup</code>: ?</p><pre><code class="language-js">&lt;InputGroup name="Location" changeID={setNumber} total={126} /&gt;
</code></pre><p>Los resultados hasta ahora?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/4yq78xas7xjcgzgnkp74.gif" class="kg-image" alt="Image description" width="1480" height="896" loading="lazy"></figure><h1 id="p-ginas-din-micas"><strong>Páginas dinámicas</strong></h1><p>Este es el último paso de nuestro proyecto. Nuestro objetivo principal es saber más sobre un personaje específico cuando hacemos clic en la tarjeta. Vamos a utilizar el sistema de módulos dinámicos de <code>react-router-dom</code>, algo como esto:?</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wx9c3gld1hvnn7nz3sda.gif" class="kg-image" alt="Image description" width="1308" height="896" loading="lazy"></figure><h3 id="carddetails-js"><strong>CardDetails.js</strong></h3><p>Para lograr nuestros objetivos, necesitamos crear un componente separado para mostrar más detalles sobre el personaje. Crearemos un nuevo archivo llamado <code>CardDetails.js</code> dentro de la carpeta <code>Card</code>.</p><p>Primero, importemos los componentes esenciales:</p><pre><code class="language-js">import React, { useState, useEffect } from "react";
import { useParams } from "react-router-dom";
</code></pre><p>Luego, necesitamos almacenar nuestra <code>api</code> y usar algunos hooks <code>useState</code>. Usaremos el <code>useParams</code> hook para obtener la identificación de la URL:?</p><pre><code class="language-js">const CardDetails = () =&gt; {
let { id } = useParams();
let [fetchedData, updateFetchedData] = useState([]);
let { name, location, origin, gender, image, status, species } = fetchedData;

let api = `https://rickandmortyapi.com/api/character/${id}`;
}
</code></pre><p>Usaremos este hook useEffect para obtener datos de nuestra API: ?</p><pre><code class="language-js">useEffect(() =&gt; {
  (async function () {
    let data = await fetch(api).then((res) =&gt; res.json());
    updateFetchedData(data);
  })();
}, [api]);
</code></pre><p>Ahora, escribamos este código que generará el nombre y la imagen de nuestro personaje: ?</p><pre><code class="language-js">return (
&lt;div className="container d-flex justify-content-center mb-5"&gt;
  &lt;div className="d-flex flex-column gap-3"&gt;
    &lt;h1 className="text-center"&gt;{name}&lt;/h1&gt;
    &lt;img className="img-fluid" src={image} alt="" /&gt;
  &lt;/div&gt;
&lt;/div&gt;
)
</code></pre><p>Ahora, escribe este código en caso de que quieras mostrar el estado actual de cada personaje:?</p><pre><code class="language-js">{(() =&gt; {
if (status === "Dead") {
  return &lt;div className="badge bg-danger fs-5"&gt;{status}&lt;/div&gt;;
} else if (status === "Alive") {
  return &lt;div className=" badge bg-success fs-5"&gt;{status}&lt;/div&gt;;
} else {
  return &lt;div className="badge bg-secondary fs-5"&gt;{status}&lt;/div&gt;;
}
})()}
</code></pre><p>A continuación, escribe este código para mostrar toda la información sobre el personaje: ?</p><pre><code class="language-js">&lt;div className="content"&gt;
  &lt;div className=""&gt;
    &lt;span className="fw-bold"&gt;Gender : &lt;/span&gt;
    {gender}
  &lt;/div&gt;
  &lt;div className=""&gt;
    &lt;span className="fw-bold"&gt;Location: &lt;/span&gt;
    {location?.name}
  &lt;/div&gt;
  &lt;div className=""&gt;
    &lt;span className="fw-bold"&gt;Origin: &lt;/span&gt;
    {origin?.name}
  &lt;/div&gt;
  &lt;div className=""&gt;
    &lt;span className="fw-bold"&gt;Species: &lt;/span&gt;
    {species}
  &lt;/div&gt;
&lt;/div&gt;
</code></pre><h3 id="app-js-5"><strong>App.js</strong></h3><p>A continuación, debemos definir nuestras rutas para que nuestro componente de enrutador dinámico funcione correctamente. Primero, importe y luego agregue este código:?</p><pre><code class="language-js">import CardDetails from "./components/Card/CardDetails";
// other codes are here

&lt;Routes&gt;
  &lt;Route path="/:id" element={&lt;CardDetails /&gt;} /&gt;
  &lt;Route path="/episodes/:id" element={&lt;CardDetails /&gt;} /&gt;
  &lt;Route path="/location/:id" element={&lt;CardDetails /&gt;} /&gt;
&lt;/Routes&gt;
</code></pre><p>Ahora, desplázate hacia abajo dentro de tu <code>App.js</code> y haz esta pequeña modificación ? para que se refiera a la página de inicio:</p><pre><code class="language-js">&lt;Card page="/" results={results} /&gt;
</code></pre><h3 id="card-js-1"><strong>Card.js</strong></h3><p>Vaya al componente de su tarjeta y realiza estos cambios: ?</p><ul><li>Primero, desestructura los nuevos accesorios e importa el <code>Link</code> desde <code>react-router-dom</code></li></ul><pre><code class="language-js">import { Link } from "react-router-dom";

const Card = ({ page, results }) =&gt; {}
</code></pre><ul><li>A continuación, envuelve todo dentro de la declaración de devolución dentro de una etiqueta de enlace: </li></ul><pre><code class="language-js">&lt;Link
  style={{ textDecoration: "none" }}
  to={`${page}${id}`}
  key={id}
  className="col-lg-4 col-md-6 col-sm-6 col-12 mb-4 position-relative text-dark"
&gt;
{/* Other codes are here */}
&lt;/Link&gt;
</code></pre><h3 id="episodes-js-1"><strong>Episodes.js</strong></h3><p>En este archivo, solo ajuste esta pequeña línea: ?</p><pre><code class="language-js">&lt;Card page="/episodes/" results={results} /&gt;
</code></pre><h3 id="location-js"><strong>Location.js</strong></h3><p>Al igual que en <code>Episodes.js</code>, solo ajusta esta pequeña línea: ?</p><pre><code class="language-js">&lt;Card page="/location/" results={results} /&gt;
</code></pre><p>Los resultados: ✨✨✨</p><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/wx9c3gld1hvnn7nz3sda.gif" class="kg-image" alt="Image description" width="1308" height="896" loading="lazy"></figure><h1 id="conclusi-n"><strong>Conclusión</strong></h1><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/uploads/articles/6596mzy60z7yb2366ffa.png" class="kg-image" alt="Image description" width="715" height="400" loading="lazy"></figure><p>¡Felicidades por leer hasta el final! Ahora puedes usar React JS y Bootstrap de manera fácil y eficiente para manejar proyectos.</p><p>También aprendiste cómo obtener datos de una API y mapear los resultados. No solo eso, también tienes un proyecto para mostrarle a tu reclutador local.</p><p>Aquí está tu medalla por leer hasta el final. ❤️</p><h2 id="las-sugerencias-y-cr-ticas-son-muy-apreciadas-">Las sugerencias y críticas son muy apreciadas<strong> ❤️</strong></h2><figure class="kg-card kg-image-card"><img src="https://dev-to-uploads.s3.amazonaws.com/i/usxsz1lstuwry3jlly4d.png" class="kg-image" alt="Alt Text" width="1000" height="245" loading="lazy"></figure><ul><li><a href="https://www.linkedin.com/in/joyshaheb/">LinkedIn/ JoyShaheb</a></li><li><a href="https://www.youtube.com/c/joyshaheb">YouTube / JoyShaheb</a></li><li><a href="https://twitter.com/JoyShaheb">Twitter / JoyShaheb</a></li><li><a href="https://www.instagram.com/joyshaheb/">Instagram / JoyShaheb</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Tutorial de React: Cómo construir el juego 2048 en React ]]>
                </title>
                <description>
                    <![CDATA[ Artículo original escrito por: Matt Sokola [https://www.freecodecamp.org/news/author/matt-sokola/] Artículo original: React Tutorial – How to Build the 2048 Game in React [https://www.freecodecamp.org/news/how-to-make-2048-game-in-react/] Traducido y adaptado por: Juan C. Guaña [/espanol/news/author/juancguana/] Hoy aprenderás a construir tu propio clon del juego 2048 en React. Lo que hace que este artículo sea único es ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/tutorial-de-react-como-construir-el-juego-2048-en-react/</link>
                <guid isPermaLink="false">6183e8f2459445092186e580</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan C. Guaña ]]>
                </dc:creator>
                <pubDate>Tue, 14 Dec 2021 03:13:14 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/11/thumb.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong>Artículo original escrito por</strong></strong></strong></strong></strong></strong></strong></strong>:</strong></strong></strong></strong></strong></strong></strong> </strong><a href="https://www.freecodecamp.org/news/author/matt-sokola/">Matt Sokola</a><br><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong>Artículo original</strong></strong></strong></strong></strong></strong></strong></strong>:</strong></strong></strong></strong></strong></strong> </strong></strong><a href="https://www.freecodecamp.org/news/how-to-make-2048-game-in-react/">React Tutorial – How to Build the 2048 Game in React</a><br><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong><strong>Traducido y adaptado por</strong></strong></strong></strong></strong></strong></strong></strong>:</strong></strong></strong></strong> </strong></strong></strong></strong><a href="https://www.freecodecamp.org/espanol/news/author/juancguana/">Juan C. Guaña</a></p><p>Hoy aprenderás a construir tu propio clon del juego 2048 en React.</p><p>Lo que hace que este artículo sea único es que nos centraremos en crear divertidas animaciones. Aparte de React, usaremos TypeScript y haremos algunas transiciones CSS usando LESS.</p><p>Solo usaremos interfaces de React modernas como hooks y la API context.</p><p>Este artículo contiene algunos recursos externos como:</p><ul><li>Juego 2048<a href="https://mateuszsokola.github.io/2048-in-react/"> (GitHub Pages)</a></li><li>Ejemplos de animación para 2048<a href="https://mateuszsokola.github.io/2048-animation-examples/"> (GitHub Pages)</a></li><li>Código fuente<a href="https://github.com/mateuszsokola/2048-in-react"> (GitHub)</a></li><li>... y un video de YouTube. Me tomó más de un mes preparar este tutorial, por lo que significaría muchísimo para mí si lo miras, presionas el botón Me gusta y te suscribes a mi canal.</li></ul><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 74.905%;" class="fluid-width-video-wrapper">
            <iframe src="https://www.youtube.com/embed/vI0QArPnkUc?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" name="fitvid0" style="box-sizing: inherit; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 22px; margin: 0px; padding: 0px; vertical-align: middle; position: absolute; top: 0px; left: 0px; width: 740px; height: 554.297px;"></iframe>
          </div>
        </div>
      </figure><p>¡Gracias!</p><h2 id="reglas-del-juego-2048"><strong>Reglas del juego 2048</strong></h2><p>En este juego, el jugador debe combinar fichas que contengan los mismos números hasta alcanzar el número 2048. Las fichas solo pueden contener valores enteros a partir de 2, y que sean una potencia de dos, como 2, 4, 8, 16, 32, etc.</p><p>Idealmente, el jugador debería alcanzar la ficha 2048 en el menor número de pasos. El tablero tiene una dimensión de 4 x 4 azulejos, por lo que puede caber hasta 16 azulejos. Si el tablero está lleno y no hay movimiento posible para hacer como unir fichas, el juego termina.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/giphy.gif" class="kg-image" alt="giphy" width="600" height="400" loading="lazy"></figure><p>Mientras creaba este tutorial, tomé atajos para enfocarme en la mecánica y las animaciones del juego. ¿De qué me deshice?</p><ul><li>En nuestro ejemplo, el juego siempre crea una nueva ficha con el número 2. Pero en la versión propia debería generar un número aleatorio (2 o 4, para que sea más difícil jugar).</li><li> Además, no manejaremos las victorias y las derrotas. Puedes jugar después de completar el número 2048, y no pasa nada cuando el tablero no se puede resolver; debes hacer clic en el botón de reinicio.</li><li>Me salté la puntuación.</li></ul><p>Si lo deseas, puedes implementar esas funciones que faltan por tu cuenta. Simplemente haz un fork de mi repositorio e impleméntelo en tu propia configuración.</p><h2 id="estructura-del-proyecto"><strong>Estructura del proyecto</strong></h2><p>La aplicación contiene los siguientes elementos:</p><ul><li>Board (componente) – responsable de renderizar mosaicos. Expone un hook llamado <code>useBoard</code>.</li><li>Grid (componente) – renderiza una cuadrícula de 4x4.</li><li>Tile (componente) – responsable de todas las animaciones relacionadas con el mosaico y de renderizar el mosaico en sí.</li><li>Game (componente) – combina todos los elementos anteriores juntos. Incluye el hook <code>useGame</code> que es responsable de hacer cumplir las reglas y restricciones del juego.</li></ul><h2 id="c-mo-construir-el-componente-tile"><strong>Cómo construir el componente Tile</strong></h2><p>Queremos invertir más tiempo en animaciones, así que comenzaré la historia desde el componente Tile. Al final, este componente es responsable de todas las animaciones del juego.</p><p>Solo hay dos animaciones bastante simples en 2048 – resaltar mosaicos y deslizarlos por el tablero. Podemos manejar esas animaciones con transiciones CSS declarando los siguientes estilos:</p><pre><code class="language-style">.tile {
  // ...
  transition-property: transform;
  transition-duration: 100ms;
  transform: scale(1);
}</code></pre><p>En el momento actual, definí solo una transición que resaltará el mosaico cuando se crea o se fusiona. Lo dejaremos así por ahora.</p><p>Consideremos cómo se supone que deben verse los metadatos de Tile, para que podamos usarlos fácilmente. Decidí llamarlo <code>TileMeta</code>, ya que no queremos que el nombre entre en conflicto con otras entidades como el componente Tile:</p><pre><code class="language-typescript">type TileMeta = {
  id: number;
  position: [number, number];
  value: number;
  mergeWith?: number;
};</code></pre><ul><li><code>id</code> – el identificador único del mosaico. Es importante para que React DOM no vuelva a renderizar todos los mosaicos desde cero en cada cambio. De lo contrario, veríamos todos los mosaicos resaltados en cada acción del jugador.</li><li><code>position</code> – la posición de la ficha en el tablero. Es un arreglo con dos elementos, la coordenada <code>x</code> e <code>y</code> (los valores posibles son <code>0</code> - <code>3</code> en ambos casos).</li><li>value – el valor del mosaico. Solo potencia de dos, a partir de <code>2</code>.</li><li><code>mergeWith</code> – (opcional) la id del mosaico que va a absorber el mosaico actual. Si está presente, el mosaico debe fusionarse con otro mosaico y desaparecer.</li></ul><h2 id="c-mo-crear-y-fusionar-mosaicos"><strong>Cómo crear y fusionar mosaicos</strong></h2><p>Queremos resaltar de alguna manera que el mosaico cambió después de la acción del jugador. Creo que la mejor manera sería cambiar la escala del mosaico para indicar que se ha creado un nuevo mosaico o se ha cambiado uno.</p><pre><code class="language-typescript">export const Tile = ({ value, position }: Props) =&gt; {
  const [scale, setScale] = useState(1);

  const prevValue = usePrevProps&lt;number&gt;(value);

  const isNew = prevCoords === undefined;
  const hasChanged = prevValue !== value;
  const shallAnimate = isNew || hasChanged;

  useEffect(() =&gt; {
    if (shallAnimate) {
      setScale(1.1);
      setTimeout(() =&gt; setScale(1), 100);
    }
  }, [shallAnimate, scale]);

  const style = {
    transform: `scale(${scale})`,
  };

  return (
    &lt;div className={`tile tile-${value}`} style={style}&gt;
      {value}
    &lt;/div&gt;
  );
};
</code></pre><p>Para activar la animación, debemos considerar dos casos:</p><ul><li>un nuevo mosaico – el valor anterior será <code>null</code>.</li><li>el mosaico cambió el valor – el valor anterior será diferente al actual.</li></ul><p>Y el resultado es el siguiente:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/giphy--1-.gif" class="kg-image" alt="giphy--1-" width="600" height="400" loading="lazy"></figure><p>Es posible que hayas notado que estoy usando un hook personalizado llamado <code>usePrevProps</code>. Éste ayuda a rastrear los valores anteriores de las propiedades del componente (props).</p><p>Podría usar referencias para recuperar los valores anteriores, pero desordenaría mi componente. Decidí extraerlo en un hook independiente, para que el código sea legible y pueda usar este hook en otros lugares.</p><p>Si deseas usarlo en tu proyecto, simplemente copia este fragmento:</p><pre><code class="language-typescript">import { useEffect, useRef } from "react";

/**
 * `usePrevProps` stores the previous value of the prop.
 *
 * @param {K} value
 * @returns {K | undefined}
 */
export const usePrevProps = &lt;K = any&gt;(value: K) =&gt; {
  const ref = useRef&lt;K&gt;();

  useEffect(() =&gt; {
    ref.current = value;
  });

  return ref.current;
};
</code></pre><h2 id="c-mo-deslizar-baldosas-por-el-tablero"><strong>Cómo deslizar baldosas por el tablero</strong></h2><p>El juego se verá chiflado sin el deslizamiento animado de las fichas por el tablero. Podemos crear fácilmente esta animación usando transiciones CSS.</p><p>Lo más conveniente será utilizar propiedades responsables del posicionamiento, como <code>left</code> y <code>top</code>. Así que necesitamos modificar nuestros estilos CSS para que se vean así:</p><pre><code class="language-style">.tile {
  position: absolute;
  // ...
  transition-property: left, top, transform;
  transition-duration: 250ms, 250ms, 100ms;
  transform: scale(1);
}</code></pre><p>Una vez que hemos declarado los estilos, podemos implementar la lógica responsable de cambiar la posición de una ficha en el tablero.</p><pre><code class="language-typescript">export const Tile = ({ value, position, zIndex }: Props) =&gt; {
  const [boardWidthInPixels, tileCount] = useBoard();
  // ...

  useEffect(() =&gt; {
    // ...
  }, [shallAnimate, scale]);

  const positionToPixels = (position: number) =&gt; {
    return (position / tileCount) * (boardWidthInPixels as number);
  };

  const style = {
    top: positionToPixels(position[1]),
    left: positionToPixels(position[0]),
    transform: `scale(${scale})`,
    zIndex,
  };

  // ...
};
</code></pre><p>Como puedes ver, la ecuación en la función <code>positionToPixels</code> necesita conocer la posición del mosaico, la cantidad total de mosaicos por fila y columna, y la longitud total del tablero en píxeles (ancho o alto, &nbsp;igual que – es un cuadrado). El valor calculado se transmite al elemento HTML como un estilo en línea.</p><p>Espere un minuto ... pero ¿qué pasa con el hook <code>useBoard</code> y la propiedad zIndex?</p><ul><li><code>useBoard</code> nos permite acceder a las propiedades de la placa dentro de los componentes secundarios sin pasarlos. El componente Tile necesita conocer el ancho y el recuento total de mosaicos para encontrar el lugar correcto en el tablero. Gracias a React Context API podemos compartir propiedades en múltiples capas de componentes sin contaminar sus propiedades (accesorios).</li><li><code>zIndex</code> es una propiedad de CSS que define el orden de los mosaicos en la pila. En nuestro caso es el id del mosaico. Como puedes ver en el gif a continuación, los mosaicos se pueden apilar unos sobre otros, por lo que zIndex nos permitió especificar cuál estará en la parte superior.</li></ul><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/a.gif" class="kg-image" alt="a" width="600" height="400" loading="lazy"></figure><h2 id="c-mo-construir-el-tablero"><strong>Cómo construir el tablero</strong></h2><p>Otra parte importante del juego es el tablero. El componente Board es responsable de renderizar la cuadrícula y los mosaicos.</p><p>Parece que el tablero ha duplicado la lógica de negocio con el componente Tile, pero hay una pequeña diferencia. El tablero contiene información sobre su tamaño (ancho y alto) y el número de columnas y filas. Es lo opuesto al Tile que solo conoce su propia posición.</p><pre><code class="language-typescript">type Props = {
  tiles: TileMeta[];
  tileCountPerRow: number;
};

const Board = ({ tiles, tileCountPerRow = 4 }: Props) =&gt; {
  const containerWidth = tileTotalWidth * tileCountPerRow;
  const boardWidth = containerWidth + boardMargin;

  const tileList = tiles.map(({ id, ...restProps }) =&gt; (
    &lt;Tile key={`tile-${id}`} {...restProps} zIndex={id} /&gt;
  ));

  return (
    &lt;div className="board" style={{ width: boardWidth }}&gt;
      &lt;BoardProvider containerWidth={containerWidth} tileCountPerRow={tileCountPerRow}&gt;
        &lt;div className="tile-container"&gt;{tileList}&lt;/div&gt;
        &lt;Grid /&gt;
      &lt;/BoardProvider&gt;
    &lt;/div&gt;
  );
};
</code></pre><p>El componente Board utiliza <code>BoardProvider</code> para distribuir el ancho del contenedor de mosaicos y la cantidad de mosaicos por fila y columna a todos los mosaicos y el componente de cuadrícula.</p><pre><code class="language-typescript">const BoardContext = React.createContext({
  containerWidth: 0,
  tileCountPerRow: 4,
});

type Props = {
  containerWidth: number;
  tileCountPerRow: number;
  children: any;
};

const BoardProvider = ({
  children,
  containerWidth = 0,
  tileCountPerRow = 4,
}: Props) =&gt; {
  return (
    &lt;BoardContext.Provider value={{ containerWidth, tileCountPerRow }}&gt;
      {children}
    &lt;/BoardContext.Provider&gt;
  );
};
</code></pre><p><code>BoardProvider</code> usa la API React Context para propagar propiedades a cada niño. Si algún componente necesita usar cualquier valor disponible en el proveedor, puede recuperarlo llamando al hook <code>useBoard</code></p><p>Voy a omitir este tema, ya que hablé más sobre él en mi <a href="https://youtu.be/H9Tx5SqWX9o">video sobre Feature Toggles en React</a>. Si deseas obtener más información sobre ellos, puedes verlo.</p><pre><code class="language-typescript">const useBoard = () =&gt; {
  const { containerWidth, tileCount } = useContext(BoardContext);

  return [containerWidth, tileCount] as [number, number];
};
</code></pre><h2 id="c-mo-construir-el-componente-del-juego"><strong>Cómo construir el componente del juego</strong></h2><p>Ahora podemos especificar las reglas del juego y exponer la interfaz para jugar. Voy a comenzar con la navegación, ya que te ayudará a comprender por qué la lógica del juego se implementa de esa manera.</p><pre><code class="language-typescript">import { useThrottledCallback } from "use-debounce";

const Game = () =&gt; {
  const [tiles, moveLeft, moveRight, moveUp, moveDown] = useGame();

  const handleKeyDown = (e: KeyboardEvent) =&gt; {
  	// disables page scrolling with keyboard arrows
    e.preventDefault();
  
    switch (e.code) {
      case "ArrowLeft":
        moveLeft();
        break;
      case "ArrowRight":
        moveRight();
        break;
      case "ArrowUp":
        moveUp();
        break;
      case "ArrowDown":
        moveDown();
        break;
    }
  };

  // protects the reducer from being flooded with events.
  const throttledHandleKeyDown = useThrottledCallback(
    handleKeyDown,
    animationDuration,
    { leading: true, trailing: false }
  );

  useEffect(() =&gt; {
    window.addEventListener("keydown", throttledHandleKeyDown);

    return () =&gt; {
      window.removeEventListener("keydown", throttledHandleKeyDown);
    };
  }, [throttledHandleKeyDown]);

  return &lt;Board tiles={tiles} tileCountPerRow={4} /&gt;;
};</code></pre><p>Como puedes ver, la lógica del juego será manejada por el hook <code>useGame</code> que expone las siguientes propiedades y métodos:</p><ul><li><code>tiles</code> – una variedad de fichas disponibles en el tablero. Utiliza el tipo <code>TileMeta</code> descrito anteriormente.</li><li><code>moveLeft</code> – una función que desliza todas las fichas hacia el lado izquierdo del tablero.</li><li><code>moveRight</code> – una función que desliza todas las fichas hacia el lado derecho del tablero.</li><li><code>moveUp</code> – una función que desliza todas las fichas a la parte superior del tablero.</li><li><code>moveDown</code> – una función que desliza todas las fichas al fondo del tablero.</li></ul><p>Usamos la devolución de llamada <code>throttledHandleKeyDown</code> para evitar que los jugadores inunden el juego con toneladas de movimientos al mismo tiempo. Básicamente, el jugador debe esperar hasta que se complete la animación antes de poder activar otro movimiento.</p><p>Este mecanismo se llama estrangulamiento (throttling). Decidí usar el hook <code>useThrottledCallback</code> del paquete <code>use-debounce</code>.</p><h2 id="c-mo-utilizar-el-hook-usegame"><strong>Cómo utilizar el hook useGame </strong></h2><p>Mencioné anteriormente que el componente Game también manejará las reglas del juego. Vamos a extraer la lógica del juego en un hook en lugar de escribirla directamente en el componente (ya que no queremos saturar el código).</p><p>El hook useGame se basa en el hook <code>useReducer</code>, que es un hook incorporado dentro de React. Comenzaré definiendo la forma del estado del reducer.</p><pre><code class="language-typescript">type TileMap = { 
  [id: number]: TileMeta;
}

type State = {
  tiles: TileMap;
  inMotion: boolean;
  hasChanged: boolean;
  byIds: number[];
};
</code></pre><p>El estado contiene los siguientes campos:</p><ul><li><code>tiles</code> – una tabla hash responsable de almacenar mosaicos. La tabla hash facilita la búsqueda de entradas por sus claves, por lo que es una combinación perfecta para nosotros, ya que queremos encontrar mosaicos por sus ids.</li><li><code>byIds</code> – un arreglo que contiene todos los ids en el orden esperado (es decir, ascendente). Debemos mantener el orden correcto de los mosaicos, para que React no vuelva a renderizar todo el tablero cada vez que cambiemos el estado.</li><li><code>hasChange</code> – realiza un seguimiento de los cambios de mosaico. Si nada ha cambiado, no se generará el nuevo mosaico.</li><li><code>inMotion</code> – determina si las fichas todavía se mueven. Si es así, el nuevo mosaico no se generará hasta que se complete el movimiento.</li></ul><h3 id="actions"><strong><strong>Actions</strong></strong></h3><p> <code>useReducer</code> requiere especificar las actions que son compatibles con este reducer.</p><pre><code class="language-typescript">type Action =
  | { type: "CREATE_TILE"; tile: TileMeta }
  | { type: "UPDATE_TILE"; tile: TileMeta }
  | { type: "MERGE_TILE"; source: TileMeta; destination: TileMeta }
  | { type: "START_MOVE" }
  | { type: "END_MOVE" };</code></pre><p>¿De qué son responsables esas actions?</p><ul><li><code>CREATE_TILE</code> – crea un nuevo mosaico y lo agrega a la tabla hash de <code>tiles</code> (mosaicos). Cambia el indicador <code>hasChange</code> a <code>false</code> ya que esta acción siempre se activa cuando se agrega una nueva ficha al tablero.</li><li><code>UPDATE_TILE</code> – actualiza un mosaico existente. No modifica la identificación, lo cual es importante para que las animaciones sigan funcionando. Lo usaremos para reposicionar el mosaico y cambiar su valor (durante las fusiones). Además, cambia el indicador <code>hasChange</code> a <code>true</code>.</li><li><code>MERGE_TILE</code> – fusiona un mosaico de origen en un mosaico de destino. Después de esta operación, el mosaico de destino cambiará su valor (se agregará el valor del mosaico de origen). Y eliminará el mosaico de origen de la tabla de <code>tiles</code> y el arreglo <code>byIds</code>.</li><li><code>START_MOVE</code> – le dice al reducer que debe esperar múltiples actions, por lo que debe esperar hasta que todas las animaciones estén completas antes de poder generar un nuevo mosaico.</li><li><code>END_MOVE</code> – le dice al reducer que se completaron todas las acciones y que puede crear de forma segura un nuevo mosaico.</li></ul><p>Si lo deseas, puedes escribir la lógica de este reducer por su cuenta o copiar la mía:</p><pre><code class="language-typescript">type TileMap = { 
  [id: number]: TileMeta;
}

type State = {
  tiles: TileMap;
  inMotion: boolean;
  hasChanged: boolean;
  byIds: number[];
};

type Action =
  | { type: "CREATE_TILE"; tile: TileMeta }
  | { type: "UPDATE_TILE"; tile: TileMeta }
  | { type: "MERGE_TILE"; source: TileMeta; destination: TileMeta }
  | { type: "START_MOVE" }
  | { type: "END_MOVE" };

const initialState: State = {
  tiles: {},
  byIds: [],
  hasChanged: false,
  inMotion: false,
};

const GameReducer = (state: State, action: Action) =&gt; {
  switch (action.type) {
    case "CREATE_TILE":
      return {
        ...state,
        tiles: {
          ...state.tiles,
          [action.tile.id]: action.tile,
        },
        byIds: [...state.byIds, action.tile.id],
        hasChanged: false,
      };
    case "UPDATE_TILE":
      return {
        ...state,
        tiles: {
          ...state.tiles,
          [action.tile.id]: action.tile,
        },
        hasChanged: true,
      };
    case "MERGE_TILE":
      const {
        [action.source.id]: source,
        [action.destination.id]: destination,
        ...restTiles
      } = state.tiles;
      return {
        ...state,
        tiles: {
          ...restTiles,
          [action.destination.id]: {
            id: action.destination.id,
            value: action.source.value + action.destination.value,
            position: action.destination.position,
          },
        },
        byIds: state.byIds.filter((id) =&gt; id !== action.source.id),
        hasChanged: true,
      };
    case "START_MOVE":
      return {
        ...state,
        inMotion: true,
      };
    case "END_MOVE":
      return {
        ...state,
        inMotion: false,
      };
    default:
      return state;
  }
};
</code></pre><p>Si no comprendes por qué definimos esas actions, no te preocupes, ahora vamos a implementar un hook que, con suerte, arrojará algo de luz al respecto.</p><h3 id="c-mo-implementar-el-hook"><strong>Cómo implementar el Hook</strong></h3><p>Veamos la función responsable de los movimientos de un jugador. Nos centraremos en el movimiento a la izquierda solo ya que los demás son casi iguales.</p><pre><code class="language-typescript">  const moveLeftFactory = () =&gt; {
    const retrieveTileIdsByRow = (rowIndex: number) =&gt; {
      const tileMap = retrieveTileMap();

      const tileIdsInRow = [
        tileMap[tileIndex * tileCount + 0],
        tileMap[tileIndex * tileCount + 1],
        tileMap[tileIndex * tileCount + 2],
        tileMap[tileIndex * tileCount + 3],
      ];

      const nonEmptyTiles = tileIdsInRow.filter((id) =&gt; id !== 0);
      return nonEmptyTiles;
    };

    const calculateFirstFreeIndex = (
      tileIndex: number,
      tileInRowIndex: number,
      mergedCount: number,
      _: number
    ) =&gt; {
      return tileIndex * tileCount + tileInRowIndex - mergedCount;
    };

    return move.bind(this, retrieveTileIdsByRow, calculateFirstFreeIndex);
  };
  
  const moveLeft = moveLeftFactory();</code></pre><p>Como puedes ver, decidí vincular dos callbacks a la función <code>move</code>. Esta técnica se llama inversión de control, por lo que el consumidor de la función podrá inyectar sus propios valores en la función ejecutada.</p><p>Si no sabes cómo funciona <code>bind</code>, debes aprender sobre él porque es una pregunta muy común en las entrevistas de trabajo.</p><p>El primer callback llamado <code>retrieveTileIdsByRow</code> es responsable de encontrar todos los mosaicos no vacíos disponibles en una fila (para movimientos horizontales – izquierda o derecha). Si el jugador hace los movimientos verticales (arriba o abajo), buscaremos todas las fichas en una columna.</p><p>El segunda callback llamado <code>calculateFirstFreeIndex</code> encuentra la posición más cercana al borde del tablero en función de los parámetros dados, como el índice de mosaico, el índice del mosaico en fila o columna, el número de mosaicos combinados y el índice máximo posible.</p><p>Ahora veremos la lógica de negocio de la función <code>move</code>. Expliqué el código de esta función en los comentarios. El algoritmo puede ser un poco complejo, y creo que será más fácil de entender si documente el código línea por línea:</p><pre><code class="language-typescript">  type RetrieveTileIdsByRowOrColumnCallback = (tileIndex: number) =&gt; number[];

  type CalculateTileIndex = (
    tileIndex: number,
    tileInRowIndex: number,
    mergedCount: number,
    maxIndexInRow: number
  ) =&gt; number;

  const move = (
    retrieveTileIdsByRowOrColumn: RetrieveTileIdsByRowOrColumnCallback,
    calculateFirstFreeIndex: CalculateTileIndex
  ) =&gt; {
    // no se pueden crear nuevos mosaicos durante el movimiento.
    dispatch({ type: "START_MOVE" });

    const maxIndex = tileCount - 1;

    // itera a través de cada fila o columna (depende del tipo de movimiento - vertical u horizontal).
    for (let tileIndex = 0; tileIndex &lt; tileCount; tileIndex += 1) {
      // recupera mosaicos en la fila o columna.
      const availableTileIds = retrieveTileIdsByRowOrColumn(tileIndex);

      // previousTile se usa para determinar si el mosaico se puede fusionar con el mosaico actual.
      let previousTile: TileMeta | undefined;
      // mergeCount ayuda a llenar los huecos creados por las combinaciones de mosaicos: dos mosaicos se convierten en uno.
      let mergedTilesCount = 0;

      // interate a través de los mosaicos disponibles.
      availableTileIds.forEach((tileId, nonEmptyTileIndex) =&gt; {
        const currentTile = tiles[tileId];

        // si el mosaico anterior tiene el mismo valor que el actual, deben fusionarse.
        if (
          previousTile !== undefined &amp;&amp;
          previousTile.value === currentTile.value
        ) {
          const tile = {
            ...currentTile,
            position: previousTile.position,
            mergeWith: previousTile.id,
          } as TileMeta;

          // retrasa la fusión en 250ms, por lo que la animación deslizante se puede completar.
          throttledMergeTile(tile, previousTile);
          // El mosaico anterior debe borrarse, ya que un solo mosaico puede fusionarse solo una vez por movimiento.
          previousTile = undefined;
          // incrementar el contador combinado a la posición correcta para que las fichas consecutivas eliminen los huecos.
          mergedTilesCount += 1;

          return updateTile(tile);
        }

        // else - los mosaicos anteriores y actuales son diferentes - mueva el mosaico al primer espacio libre.
        const tile = {
          ...currentTile,
          position: indexToPosition(
            calculateFirstFreeIndex(
              tileIndex,
              nonEmptyTileIndex,
              mergedTilesCount,
              maxIndex
            )
          ),
        } as TileMeta;

        // el mosaico anterior se convierte en el mosaico actual para comprobar si el siguiente mosaico se puede fusionar con este.
        previousTile = tile;

        // solo si el mosaico ha cambiado de posición, se actualizará
        if (didTileMove(currentTile, tile)) {
          return updateTile(tile);
        }
      });
    }

    // espere hasta el final de todas las animaciones.
    setTimeout(() =&gt; dispatch({ type: "END_MOVE" }), animationDuration);
  };</code></pre><p>El código completo de este hook tiene más de 400 líneas de código, así que en lugar de pegarlo aquí, decidí mantenerlo en GitHub, así que <a href="https://github.com/mateuszsokola/2048-in-react/blob/master/src/components/Game/hooks/useGame/useGame.ts">revisa el código completo allí.</a></p><h2 id="tarea"><strong>Tarea</strong></h2><p>Mencioné anteriormente que faltan algunas características. Si deseas comprender el código en profundidad, puedes bifurcar mi repositorio e implementar las siguientes características:</p><ul><li>Puntuación – puedes definir tu propio algoritmo.</li><li>Soporte de victorias y pérdidas</li><li>Para la generación de mosaicos nuevos, elije un valor de mosaico aleatorio – ya sea 2 o 4. El 4 no debe aparecer menos del 5% de las veces.</li></ul><p>Si deseas que revise tu código, puedes invitarme a tu solicitud de pull request en GitHub – mi nombre de usuario es mateuszsokola. Tal vez grabe un video sobre cómo reviso tu código.</p><h2 id="resumen"><strong>Resumen</strong></h2><p>Espero que hayas disfrutado de mi tutorial. Esta vez decidí centrarme en la esencia del tema en lugar de construir React y CSS básicos, así que me salté esas partes básicas. Creo que hace que este artículo sea más fácil de digerir.</p><p>¿Algún comentario o pregunta? <a href="https://twitter.com/msokola">¡Grítame en twitter!</a></p><p>Si este artículo te resultó útil, compártalo para que más desarrolladores puedan aprender de él. De vez en cuando <a href="https://www.youtube.com/channel/UCJV16_5c4A0amyBZSI4yP6A">publico videos en mi canal de YouTube</a>, y sería genial si te suscribes a mi canal, presionas el botón me gusta y dejas un comentario debajo de tu video favorito.</p><p>¡Manténganse al tanto!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ 5 lecciones clave de React que los tutoriales no te enseñan ]]>
                </title>
                <description>
                    <![CDATA[ Artículo original escrito por: Reed Barger [https://www.freecodecamp.org/news/author/reed/] Artículo original: 5 Key React Lessons the Tutorials Don't Teach You [https://www.freecodecamp.org/news/5-react-lessons-tutorials-dont-teach/] Traducido y adaptado por: Juan C. Guaña [/espanol/news/author/juancguana/] Hay muchos conceptos y lecciones esenciales que los desarrolladores de React necesitan saber y que simplemente no se tratan en la mayoría de ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/5-lecciones-clave-de-react-que-los-tutoriales-no-te-ensenan/</link>
                <guid isPermaLink="false">6175634b56587409993543d0</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan C. Guaña ]]>
                </dc:creator>
                <pubDate>Thu, 11 Nov 2021 12:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/10/5-key-lessons-react-tutorials-dont-teach.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><strong><strong><strong><strong><strong><strong><strong><strong>Artículo original escrito por</strong></strong></strong></strong>:</strong></strong></strong> </strong><a href="https://www.freecodecamp.org/news/author/reed/">Reed Barger</a><br><strong><strong><strong><strong><strong><strong><strong><strong>Artículo original</strong></strong></strong></strong>:</strong></strong></strong> </strong><a href="https://www.freecodecamp.org/news/5-react-lessons-tutorials-dont-teach/">5 Key React Lessons the Tutorials Don't Teach You</a><br><strong><strong><strong><strong><strong><strong><strong><strong>Traducido y adaptado por</strong></strong></strong></strong>:</strong></strong> </strong></strong><a href="https://www.freecodecamp.org/espanol/news/author/juancguana/">Juan C. Guaña</a></p><p>Hay muchos conceptos y lecciones esenciales que los desarrolladores de React necesitan saber y que simplemente no se tratan en la mayoría de los tutoriales.</p><p>He seleccionado cuidadosamente los temas que creo que son algunos de los más importantes que debes conocer, pero pocos artículos se han dedicado a cubrirlos en detalle.</p><p>Echemos un vistazo a cinco lecciones clave de React que vale la pena conocer y que quizás no encuentres en otro lugar.</p><h2 id="1-c-mo-se-actualiza-realmente-el-estado-de-react"><strong>1. Cómo se actualiza realmente el estado de React</strong></h2><p>Como desarrollador de React, sabes que el estado se puede crear y actualizar con los hooks <code>useState</code> y <code>useReducer</code>.</p><p>Pero, ¿qué sucede exactamente cuando actualiza el estado de un componente con cualquiera de estos hooks? ¿El estado se actualiza inmediatamente o se hace en algún momento posterior?</p><p>Veamos el siguiente código, que es una aplicación de contador muy simple. Como era de esperar, puede hacer clic en el botón y nuestro contador aumenta en 1.</p><pre><code class="language-js">import React from 'react';

export default function App() {
  const [count, setCount] = React.useState(0)

  function addOne() {
    setCount(count + 1);
  }

  return (
    &lt;div&gt;
      &lt;h1&gt;Count: {count}&lt;/h1&gt; {/* 1 (as we expect) */}

      &lt;button onClick={addOne}&gt;+ 1&lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre><p>Pero, ¿qué pasa si intentamos agregar una línea adicional, que también actualiza nuestro recuento en uno? ¿Qué crees que sucederá?</p><p>Cuando haces clic en el botón, ¿nuestro contador mostrado aumentará en uno o dos?</p><pre><code class="language-js">import React from 'react';

export default function App() {
  const [count, setCount] = React.useState(0)

  function addOne() {
    setCount(count + 1);
    setCount(count + 1);
  }

  return (
    &lt;div&gt;
      &lt;h1&gt;Count: {count}&lt;/h1&gt; {/* 1?! */}

      &lt;button onClick={addOne}&gt;+ 1&lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre><p>¡Si ejecutamos este código, vemos que se incrementa solo en uno! A pesar de intentar incrementar el contador en uno dos veces, con dos actualizaciones de estado separadas.</p><p><em>¿Por qué nuestro contador muestra 1, a pesar de incrementar claramente el estado en 1 dos veces?</em></p><p>La razón de esto es que React programa una actualización de estado que se realizará cuando actualizamos el estado por primera vez. Debido a que solo está programado y no se realiza de inmediato (es asíncrono y no síncrono), nuestra variable <code>contador</code> no se actualiza antes de intentar actualizarla por segunda vez.</p><p>En otras palabras, debido a que la actualización del estado está programada, no se realiza de inmediato, la segunda vez que llamamos a <code>setCount</code>, <code>count</code> sigue siendo solo <code>0</code>, no <code>1</code>.</p><p>La forma en que podemos solucionar esto para actualizar el estado de manera confiable, a pesar de que las actualizaciones de estado son asincrónicas, es usar la función interna que está disponible dentro de la función setter de <code>useState</code>.</p><p>Esto nos permite obtener el estado anterior y devolver el valor que queremos que tenga en el cuerpo de la función interna. Cuando usamos este patrón, vemos que se incrementa en dos como queríamos originalmente:</p><pre><code class="language-js">import React from 'react';

export default function App() {
  const [count, setCount] = React.useState(0)

  function addOne() {
    setCount(prevCount =&gt; prevCount + 1); // 1
    setCount(prevCount =&gt; prevCount + 1); // 2
  }

  return (
    &lt;div&gt;
      &lt;h1&gt;Count: {count}&lt;/h1&gt;
      &lt;button onClick={addOne}&gt;+ 1&lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre><h2 id="2-es-mejor-usar-varios-efectos-en-lugar-de-uno"><strong>2. Es mejor usar varios efectos en lugar de uno</strong></h2><p>Al realizar un efecto secundario, la mayoría de los desarrolladores de React usarán <code>useEffect</code> solo una vez e intentarán realizar múltiples efectos secundarios dentro de la misma función de efecto.</p><p>¿Cómo se ve eso? A continuación, puedes ver dónde obtenemos datos de publicaciones y comentarios en un hook useEffect para colocarlos en sus respectivas variables de estado:</p><pre><code class="language-js">import React from "react";

export default function App() {
  const [posts, setPosts] = React.useState([]);
  const [comments, setComments] = React.useState([]);

  React.useEffect(() =&gt; {
    // fetching post data
    fetch("https://jsonplaceholder.typicode.com/posts")
      .then((res) =&gt; res.json())
      .then((data) =&gt; setPosts(data));

    // fetching comments data
    fetch("https://jsonplaceholder.typicode.com/comments")
      .then((res) =&gt; res.json())
      .then((data) =&gt; setComments(data));
  }, []);

  return (
    &lt;div&gt;
      &lt;PostsList posts={posts} /&gt;
      &lt;CommentsList comments={comments} /&gt;
    &lt;/div&gt;
  );
}</code></pre><p>En lugar de intentar agrupar todos sus efectos secundarios en un solo hook de efecto, del mismo modo que puedes usar el hook <code>useState</code> más de una vez, puede usar varias veces <code>useEffect</code>.</p><p>Hacerlo nos permite separar nuestras diferentes acciones en diferentes efectos para una mejor separación de preocupaciones.</p><p>Una mejor separación de preocupaciones es un beneficio importante que brindan los hooks de React en comparación con el uso de métodos de ciclo de vida dentro de los componentes de la clase.</p><p>En métodos como <code>componentDidMount</code>, por ejemplo, era necesario incluir cualquier acción que queramos realizar después de que se montara nuestro componente. No puede dividir sus efectos secundarios en varios métodos – cada método del ciclo de vida en las clases se puede usar una vez y solo una vez.</p><p>El principal beneficio de React hooks es que podemos dividir nuestro código en función de lo que está haciendo. No solo podemos separar en múltiples efectos las acciones que estamos realizando después de renderizar, sino que también podemos co-ubicar nuestro estado:</p><pre><code class="language-js">import React from "react";

export default function App() {
  const [posts, setPosts] = React.useState([]);
  React.useEffect(() =&gt; {
    fetch("https://jsonplaceholder.typicode.com/posts")
      .then((res) =&gt; res.json())
      .then((data) =&gt; setPosts(data));
  }, []);

  const [comments, setComments] = React.useState([]);
  React.useEffect(() =&gt; {
    fetch("https://jsonplaceholder.typicode.com/comments")
      .then((res) =&gt; res.json())
      .then((data) =&gt; setComments(data));
  }, []);

  return (
    &lt;div&gt;
      &lt;PostsList posts={posts} /&gt;
      &lt;CommentsList comments={comments} /&gt;
    &lt;/div&gt;
  );
}</code></pre><p>Esto significa que podemos poner el hook <code>useState</code> con el hook <code>useEffect</code> con el que está relacionado. Esto ayuda a organizar nuestro código mucho mejor y a comprender mejor lo que está haciendo de un vistazo.</p><h2 id="3-no-optimizar-las-funciones-que-actualizan-el-estado-usestate-usereducer-"><strong>3. No optimizar las funciones que actualizan el estado (useState, useReducer)</strong></h2><p>Una tarea común cada vez que pasamos una función callback desde llamada de un componente padre a un componente hijo es evitar que se vuelva a crear, a menos que sus argumentos hayan cambiado.</p><p>Podemos realizar esta optimización con la ayuda del hook <code>useCallback</code>.</p><p>useCallback fue creado específicamente para funciones callback que se pasan a componentes hijos para asegurarse de que no se vuelvan a recrear innecesariamente, lo que genera un impacto en el rendimiento de nuestros componentes cada vez que se vuelve a renderizar.</p><p>Esto se debe a que cada vez que nuestro componente padre se vuelve a renderizar, también se volverán a renderizar todos los componentes hijos. Esto es lo que hace que nuestras funciones callback se vuelvan a crear en cada re-renderización.</p><p>Sin embargo, si estamos usando una función setter para actualizar el estado que hemos creado con los hooks useState o useReducer, no necesitamos envolver eso con useCallback.</p><p>En otras palabras, no es necesario hacer esto:</p><pre><code class="language-js">import React from "react";

export default function App() {
  const [text, setText] = React.useState("")

  // Don't wrap setText in useCallback (it won't change as is)
  const handleSetText = React.useCallback((event) =&gt; {
    setText(event.target.value);
  }, [])

  return (
    &lt;form&gt;
      &lt;Input text={text} handleSetText={handleSetText} /&gt;
      &lt;button type="submit"&gt;Submit&lt;/button&gt;
    &lt;/form&gt;
  );
}

function Input({ text, handleSetText }) {
  return(
    &lt;input type="text" value={text} onChange={handleSetText}  /&gt;
  )
}</code></pre><p>La razón proviene directamente de la documentación de React:</p><blockquote>React garantiza que la identidad de la función <code>setState</code> es estable y no cambiará en subsecuentes renderizados. Es por eso que es seguro omitirla de la lista de dependencias de <code>useEffect</code> o <code>useCallback</code>.</blockquote><p>Por lo tanto, no solo no necesitamos optimizarlo innecesariamente con useCallback, sino que tampoco necesitamos incluirlo como una dependencia dentro de useEffect porque no cambiará.</p><p>Es importante tener en cuenta esto porque, en muchos casos, puede reducir el código que necesitamos usar. Y lo más importante, es un intento improductivo de optimizar el código, ya que puede incurrir en problemas de rendimiento propios.</p><h2 id="4-el-hook-useref-puede-preservar-el-estado-en-todas-las-renderizaciones"><strong>4. El hook useRef puede preservar el estado en todas las renderizaciones</strong></h2><p>Como desarrolladores de React, a veces es muy útil poder hacer referencia a un elemento de React dado con la ayuda de un ref (referencia). Creamos refs en React con la ayuda del hook <code>useRef</code>.</p><p>Sin embargo, es importante tener en cuenta que <code>useRef</code> no solo es útil para hacer referencia a un determinado elemento DOM. La documentación de React lo dice en sí misma:</p><blockquote>El objeto “ref” es un contenedor genérico cuya propiedad <code>current</code> es mutable y puede contener cualquier valor.</blockquote><p>Existen ciertos beneficios para poder almacenar y actualizar valores con <code>useRef</code>. Nos permite almacenar un valor que no estará en la memoria y que no se borrará al volver a renderizar.</p><p>Si quisiéramos realizar un seguimiento de un valor en las representaciones con la ayuda de una variable simple, se reinicializaría cada vez que se procese el componente. Sin embargo, si usas una referencia, el valor almacenado en ella permanecerá constante en todas las representaciones del componente.</p><p><em>¿Cuál es un caso de uso para aprovechar useRef de esta manera?</em></p><p>Esto podría ser útil en el caso de que quisiéramos realizar un efecto secundario determinado solo en el renderizado inicial, por ejemplo:</p><pre><code class="language-js">import React from "react";

export default function App() {
  const [count, setCount] = React.useState(0);
  const ref = React.useRef({ hasRendered: false });

  React.useEffect(() =&gt; {
    if (!ref.current.hasRendered) {
      ref.current.hasRendered = true;
      console.log("perform action only once!");
    }
  }, []);

  return (
    &lt;div&gt;
      &lt;button onClick={() =&gt; setCount(count + 1)}&gt;Count: {count}&lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre><p>Intente ejecutar este código usted mismo.</p><p>Como verá, no importa cuántas veces se haga clic en el botón, se actualice el estado y se vuelva a renderizar, la acción que queremos realizar (ver <code>console.log</code>) solo se realiza una vez.</p><h2 id="5-c-mo-evitar-que-la-aplicaci-n-en-react-se-bloquee"><strong>5. Cómo evitar que la aplicación en React se bloquee</strong></h2><p>Una de las lecciones más importantes que los desarrolladores de React deben saber, especialmente si no han enviado una aplicación React a la web, es qué hacer con los errores no detectados.</p><p>En el siguiente ejemplo, intentamos mostrar un componente Header en nuestra aplicación, pero estamos realizando una acción que da como resultado un error. Es decir, intentar obtener una propiedad a partir de un valor nulo:</p><pre><code class="language-js">import React from "react";

export default function App() {
  return (
    &lt;&gt;
      &lt;Header /&gt;
    &lt;/&gt;
  );
}

function Header() {
  const user = null;

  return &lt;h1&gt;Hello {user.name}&lt;/h1&gt;; // error!
}</code></pre><p>Si enviamos este código a producción, veremos una pantalla en blanco exactamente como esta:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/5-key-lessons-1.png" class="kg-image" alt="5-key-lessons-1" width="600" height="400" loading="lazy"></figure><p>¿Por qué no vemos nada?</p><p>Nuevamente, podemos encontrar la respuesta para esto dentro de la documentación de React:</p><blockquote>A partir de React 16, los errores que no fueron detectados por ningún límite de error resultarán en el desmontaje de todo el árbol de componentes de React.</blockquote><p>Mientras está en desarrollo, verás un gran mensaje de error rojo con un seguimiento de la pila que le indica dónde se puede encontrar el error. Sin embargo, cuando tu aplicación esté activa, solo verás una pantalla en blanco.</p><p>Este no es el comportamiento deseado que quieres para tu aplicación.</p><p>Pero hay una manera de solucionarlo, o al menos mostrarles a tus usuarios algo que les diga que se produjo un error si la aplicación falla accidentalmente. Puedes envolver el árbol de componentes en lo que se llama un límite de error (error boundary).</p><p>Los límites de error son componentes que nos permiten detectar errores y mostrar a los usuarios un mensaje de respaldo que les dice que ocurrió algo incorrecto. Eso podría incluir instrucciones sobre cómo descartar el error (como volver a cargar la página).</p><p>Podemos usar un límite de error con la ayuda del paquete <code>react-error-boundary</code>. Podemos ajustarlo al componente que creemos que es propenso a errores. También se puede envolver alrededor de todo el árbol de componentes de la aplicación:</p><pre><code class="language-js">import React from "react";
import { ErrorBoundary } from "react-error-boundary";

export default function App() {
  return (
    &lt;ErrorBoundary FallbackComponent={ErrorFallback}&gt;
      &lt;Header /&gt;
    &lt;/ErrorBoundary&gt;
  );
}

function Header() {
  const user = null;

  return &lt;h1&gt;Hello {user.name}&lt;/h1&gt;;
}

function ErrorFallback({ error }) {
  return (
    &lt;div role="alert"&gt;
      &lt;p&gt;Oops, there was an error:&lt;/p&gt;
      &lt;p style={{ color: "red" }}&gt;{error.message}&lt;/p&gt;
    &lt;/div&gt;
  );
}</code></pre><p>También puedes mostrar el mensaje de error como desees y diseñarlo como lo haría con cualquier componente normal.</p><p>El resultado que obtenemos cuando ocurre un error es mucho mejor:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/5-key-lessons-2.png" class="kg-image" alt="5-key-lessons-2" width="600" height="400" loading="lazy"></figure> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Contexto de ejecución de JavaScript y Hoisting explicados con ejemplos de código ]]>
                </title>
                <description>
                    <![CDATA[ Artículo original escrito por: Tapas Adhikary [https://www.freecodecamp.org/news/author/tapas/] Artículo original: JavaScript Execution Context and Hoisting Explained with Code Examples [https://www.freecodecamp.org/news/javascript-execution-context-and-hoisting/] Traducido y adaptado por: Juan C. Guaña [/espanol/news/author/juancguana/] JavaScript es un lenguaje de programación fácil de aprender en comparación con muchos de sus homólogos. Sin embargo, algunos conceptos básicos necesitan un ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/contexto-de-ejecucion-de-javascript-y-hoisting-explicados-con-ejemplos-de-codigo/</link>
                <guid isPermaLink="false">614dd6d06534fb0945712873</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan C. Guaña ]]>
                </dc:creator>
                <pubDate>Fri, 15 Oct 2021 12:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/09/freeCodeCamp-Cover-4.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><strong><strong><strong><strong>Artículo original escrito por</strong></strong>: </strong></strong><a href="https://www.freecodecamp.org/news/author/tapas/">Tapas Adhikary</a><br><strong><strong><strong><strong>Artículo original</strong></strong>: </strong></strong><a href="https://www.freecodecamp.org/news/javascript-execution-context-and-hoisting/">JavaScript Execution Context and Hoisting Explained with Code Examples</a><br><strong><strong><strong><strong>Traducido y adaptado por</strong></strong>:</strong> </strong><a href="https://www.freecodecamp.org/espanol/news/author/juancguana/">Juan C. Guaña</a></p><p>JavaScript es un lenguaje de programación fácil de aprender en comparación con muchos de sus homólogos. Sin embargo, algunos conceptos básicos necesitan un poco más de atención si quieres comprender, depurar y escribir un mejor código.</p><p>En este artículo, vamos a aprender acerca de dos conceptos,</p><ul><li>Contexto de ejecución</li><li>Hoisting</li></ul><p>Como principiante en JavaScript, comprender estos conceptos te ayudará a comprender las palabras clave <code>this</code>, <code>scope</code> y <code>closure</code> de manera mucho más cómoda. Así que disfruta y sigue leyendo.</p><h1 id="contexto-de-ejecuci-n-en-javascript"><strong>Contexto de ejecución en JavaScript</strong></h1><p>En general, un archivo fuente de JavaScript tendrá varias líneas de código. Como desarrolladores, organizamos el código en variables, funciones, estructuras de datos como objetos, matrices, y más.</p><p>Un <code>Ámbito Léxico</code> determina cómo y dónde escribimos nuestro código físicamente. Eche un vistazo al siguiente código:</p><pre><code class="language-js">function doSomething() {
  var age= 7;
  // Some more code
 }
</code></pre><p>En el código anterior, la variable edad está léxicamente dentro de la función <code>doSomething</code>.</p><p>Tenga en cuenta que nuestro código no se ejecuta como está. Tiene que ser traducido por el compilador a un código de bytes comprensible por computadora. Por lo tanto, el compilador necesita mapear lo que está colocado léxicamente en un lugar significativo y válido.</p><p>Por lo general, habrá más de un <code>Ámbito Léxico</code> en su código. Sin embargo, no todos los ámbitos se ejecutan a la vez.</p><p>El ámbito que ayuda a que se ejecute el código se denomina <code>Contexto de Ejecución</code>. Es el código que se está ejecutando actualmente y todo lo que lo rodea que lo ayuda a ejecutarlo.</p><p>Puede haber muchos <code>Ámbitos Léxicos</code> disponibles, pero el <code>Contexto de Ejecución</code> administra el código que se está ejecutando actualmente.</p><p>Mira la imagen a continuación para comprender la diferencia entre un Ámbito Léxico y un Contexto de Ejecución:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/04/lexical.gif" class="kg-image" alt="lexical" width="600" height="400" loading="lazy"><figcaption>Ámbito Léxico vs Contexto de Ejecución</figcaption></figure><p>Entonces, ¿qué sucede exactamente en el contexto de ejecución? El código se analiza línea por línea, genera código de bytes ejecutable, asigna memoria y se ejecuta.</p><p>Tomemos la misma función que hemos visto anteriormente. ¿Qué crees que puede pasar cuando se ejecuta la siguiente línea?</p><pre><code class="language-js">var age = 7;
</code></pre><p>Hay muchas cosas que suceden detrás de escena. Ese fragmento de código fuente pasa por las siguientes fases antes de que finalmente se ejecute:</p><ul><li><strong>Tokenización:</strong> en esta fase, la cadena de código fuente se divide en varios fragmentos significativos llamados <code>Tokens</code>. Por ejemplo, el código <code>var age = 7;</code> se tokeniza en var, age, =, 7 y,;.</li><li><strong><strong>Parsing: </strong></strong>La siguiente fase es el análisis, donde una matriz de tokens se convierte en un árbol de elementos anidados comprendidos por la gramática del idioma. Este árbol se llama AST (árbol de sintaxis abstracta).</li><li><strong>Generación de código:</strong> En esta fase, el AST creado en la fase de análisis se convierte en código de bytes ejecutable. Este código de bytes ejecutable luego se optimiza aún más mediante el compilador JIT (Just-In-Time).</li></ul><p>La siguiente imagen animada muestra la transición del código fuente al código de bytes ejecutable.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/04/execution_steps.gif" class="kg-image" alt="execution_steps" width="600" height="400" loading="lazy"><figcaption>Código fuente a código byte ejecutable</figcaption></figure><p>Todas estas cosas suceden en un <code>Contexto de Ejecución</code>. Entonces, el contexto de ejecución es el entorno donde se ejecuta una parte específica del código.</p><p>Hay dos tipos de contextos de ejecución:</p><ul><li>Contexto de ejecución global o Global Execution Context (GEC) </li><li>Contexto de ejecución de funciones o Function Execution Context (FEC)</li></ul><p>Y cada uno de los contextos de ejecución tiene dos fases:</p><ul><li>Fase de creación </li><li>Fase de ejecución</li></ul><p>Echemos un vistazo detallado a cada uno de ellos y comprendamos un poco mejor.</p><h2 id="contexto-de-ejecuci-n-global-gec-en-javascript"><strong>Contexto de ejecución global (GEC) en JavaScript</strong></h2><p>Siempre que ejecutamos código JavaScript, se crea un contexto de ejecución global (también conocido como contexto de ejecución base). El contexto de ejecución global tiene dos fases.</p><h3 id="fase-de-creaci-n"><strong>Fase de creación</strong></h3><p>En la fase de creación, se crean dos cosas únicas:</p><ul><li>Un objeto global llamado <code>window</code> (para JavaScript del lado del cliente). </li><li>Una variable global llamada <code>this</code>.</li></ul><p>Si hay alguna variable declarada en el código, se asigna un espacio en la memoria para la variable. La variable se inicializa con un valor único llamado <code>undefined</code>. Si hay una <code>función</code> en el código, se coloca directamente en la memoria. Aprenderemos más sobre esta parte en la sección <code>Hoisting</code> más adelante.</p><h3 id="fase-de-ejecuci-n"><strong>Fase de ejecución</strong></h3><p>La ejecución del código comienza en esta fase. Aquí tiene lugar la asignación de valor de las variables globales. Ten en cuenta que aquí no se invoca ninguna función, como sucede en el contexto de ejecución de funciones. Veremos eso en un rato.</p><p>Entendamos ambas fases con un par de ejemplos.</p><h4 id="ejemplo-1-cargar-un-script-vac-o"><strong>Ejemplo 1: Cargar un script vacío</strong><br></h4><p>Cree un archivo JavaScript vacío con el nombre <code>index.js</code>. Ahora cree un archivo HTML con el siguiente contenido:</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta charset="UTF-8"&gt;
    &lt;meta http-equiv="X-UA-Compatible" content="IE=edge"&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
    &lt;title&gt;Document&lt;/title&gt;
    &lt;script src='./index.js'&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
    I'm loading an empty script
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>Ten en cuenta que estamos importando el archivo de script vacío en el archivo HTML usando la etiqueta <code>&lt;script&gt;</code>.</p><p>Carga el archivo HTML en el navegador y abre Chrome DevTools (generalmente usando la tecla <code>F12</code>) o equivalente para otros navegadores. Ve a la pestaña de la <code>console</code>, escribe <code>window</code> y presiona enter. Deberías ver el valor del objeto <code>Window</code> del navegador.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-102.png" class="kg-image" alt="image-102" width="600" height="400" loading="lazy"><figcaption>Objeto Window</figcaption></figure><p>Ahora, escribe la palabra <code>this</code> y presiona enter. Debería ver el mismo valor del objeto <code>Window</code> impreso en la consola del navegador.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-103.png" class="kg-image" alt="image-103" width="600" height="400" loading="lazy"><figcaption>Valor de 'this'</figcaption></figure><p>Genial, ahora intenta comprobar si la <code>window</code> es igual a <code>this</code>. Sí lo es.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-104.png" class="kg-image" alt="image-104" width="600" height="400" loading="lazy"><figcaption>window es igual a 'this'</figcaption></figure><p>Muy bien, entonces, ¿qué hemos aprendido?</p><ul><li>El Contexto de Ejecución Global se crea cuando cargamos el archivo JavaScript, incluso cuando está vacío.</li><li>Se crea dos cosas especiales para nosotros en su fase de creación, que es el objeto <code>window</code> y <code>this</code>.</li><li>En el Contexto de Ejecución Global, el objeto de <code>window</code> y <code>this</code> son iguales.</li><li>No hay nada que ejecutar, ya que el archivo de secuencia de comandos está en blanco. Entonces no pasa nada en la fase de ejecución.</li></ul><h4 id="ejemplo-2-con-variables-y-funciones"><strong>Ejemplo 2: Con variables y funciones</strong></h4><p>Veamos ahora un ejemplo con algo de código en el archivo JavaScript. Agregaremos una variable (blog) con un valor asignado. También definiremos una función con el nombre <code>logBlog</code>.</p><pre><code class="language-js">var blog = 'freeCodeCamp';

function logBlog() {
  console.log(this.blog); 
}
</code></pre><p>En la fase de creación:</p><ul><li>Se crea el objeto global <code>window</code> y la variable <code>this</code>. </li><li>Se asigna un espacio en la memoria &nbsp;para la variable <code>blog</code> y la función <code>logBlog</code>. </li><li>La variable <code>blog</code> se inicializa con un valor especial <code>undefined</code>. La función <code>logBlog</code> se coloca directamente en la memoria</li></ul><p>En fase de ejecución:</p><ul><li>El valor <code>freeCodeCamp</code> se asigna a la variable <code>blog</code>.</li><li>Como hemos definido la función, pero aún no la hemos llamado, la ejecución de la función no tiene lugar. Llamaremos a la función y veremos qué sucede cuando aprendamos sobre el Contexto de Ejecución de la Función.</li></ul><h2 id="contexto-de-ejecuci-n-de-funciones-fec-en-javascript"><strong>Contexto de ejecución de funciones (FEC) en JavaScript</strong></h2><p>Cuando invocamos una función, se crea un Contexto de Ejecución de Función. Extendamos el mismo ejemplo que usamos anteriormente, pero esta vez llamaremos a la función.</p><pre><code class="language-js">var blog = 'freeCodeCamp';

function logBlog() {
  console.log(this.blog); 
}

// Llamemos a la función
logBlog();</code></pre><p>El contexto de ejecución de la función pasa por las mismas fases, creación y ejecución.</p><p>La fase de ejecución de la función tiene acceso a un valor especial llamado <code>arguments</code>. Son los argumentos pasados ​​a la función. En nuestro ejemplo, no se pasan argumentos.</p><p>Ten en cuenta que el objeto <code>window</code> y la variable <code>this</code> creada en el contexto de ejecución global todavía son accesibles en este contexto.</p><p>Cuando una función invoca a otra función, se crea un nuevo contexto de ejecución de función para la nueva llamada a la función. Cada uno de los contextos de ejecución de la función determina el alcance o <code>scope</code> de las variables utilizadas en las funciones respectivas.</p><h1 id="hoisting-en-javascript"><strong><strong>Hoisting </strong>e<strong>n JavaScript</strong></strong></h1><p>Espero que hayas disfrutado aprendiendo sobre el <code>Contexto de Ejecución</code>. Pasemos a otro concepto fundamental llamado <code>Hoisting</code>. Cuando escuché por primera vez sobre <code>Hoisting</code>, me tomó un tiempo darme cuenta de que algo andaba muy mal con el nombre de <code>Hoisting</code>.</p><p>En el idioma inglés, hoisting significa levantar algo usando cuerdas y poleas. El nombre puede inducirlo al error de pensar que el motor de JavaScript extrae las variables y funciones en una fase de ejecución de código específica. Bueno, esto no es lo que pasa.</p><p>Entonces, entendamos el <code>Hoisting</code> usando el concepto de <code>Contexto de Ejecución</code>.</p><h2 id="variable-hoisting-en-javascript"><strong><strong>Variable</strong> h<strong>oisting</strong> e<strong>n JavaScript</strong></strong></h2><p>Eche un vistazo al siguiente ejemplo y adivina el resultado:</p><pre><code class="language-js">console.log(name);
var name;

</code></pre><p>Estoy seguro de que ya lo adivinaste. Es lo siguiente:</p><pre><code class="language-shell">undefined
</code></pre><p>Sin embargo, la pregunta es ¿por qué? Supongamos que usamos un código similar en algún otro lenguaje de programación. En ese caso, es posible que obtengamos un error que indique que el nombre de la variable no está declarado y que estamos intentando acceder a él mucho antes. La respuesta está en el contexto de ejecución.</p><p>En la fase de <code>creación</code>,</p><ul><li>Se asigna un espacio en la memoria para el <code>nombre</code> de la variable y</li><li>Se asigna el valor especial <code>undefined</code> a la variable.</li></ul><p>En la fase de <code>ejecución</code>,</p><ul><li>Se ejecutará la instrucción <code>console.log (name)</code>.</li></ul><p>Este mecanismo de asignación de memoria para variables e inicialización con el valor <code>undefined</code> en la fase de creación del contexto de ejecución se denomina <code>Variable Hoisting</code>.</p><blockquote>El valor especial <code>undefined</code> significa que se declara una variable, pero no se asigna ningún valor.</blockquote><p>Si le asignamos a la variable un valor como este:</p><pre><code class="language-js">name = 'freeCodeCamp';</code></pre><p>La fase de ejecución asignará este valor a la variable.</p><h2 id="function-hoisting-en-javascript"><strong><strong>Function Hoisting </strong>e<strong>n JavaScript</strong></strong></h2><p>Ahora hablemos de <code>Function Hoisting</code>. Sigue el mismo patrón que la <code>Variable Hoisting</code>.</p><p>La fase de creación del contexto de ejecución coloca la declaración de la función en la memoria y la fase de ejecución la ejecuta. Eche un vistazo al siguiente ejemplo:</p><pre><code class="language-js">// Invocar la función functionA
functionA();

// Declarar la función functionA
function functionA() {
 console.log('Function A');
 // Invocar la función FunctionB    
 functionB();
}

// Declarar la función FunctionB
function functionB() {
 console.log('Function B');
}</code></pre><p>El resultado es el siguiente:</p><pre><code class="language-shell">Function A
Function B</code></pre><ul><li>El contexto de ejecución crea la memoria para la función y coloca la declaración de función completa de <code>functionA</code> en ella.</li><li>Las funciones crean su propio contexto de ejecución. Entonces sucede algo similar con la <code>functionB</code>.</li><li>A continuación, las funciones se ejecutan en su contexto de ejecución respectivamente.</li></ul><p>Poner toda la declaración de función en la memoria en la fase de creación se llama <code>Function Hoisting</code>.</p><h2 id="algunas-reglas-b-sicas"><strong>Algunas reglas básicas</strong></h2><p>Dado que ahora entendemos el concepto de <code>Hoisting</code>, comprendamos algunas reglas básicas:</p><ul><li>Siempre defina variables y funciones antes de usarlas en su código. Reduce las posibilidades de errores sorpresa y depuración de pesadilla.</li><li>Hoisting es solo para la declaración de funciones, no para la inicialización. A continuación se muestra un ejemplo de inicialización de una función en donde la ejecución del código se romperá.</li></ul><pre><code class="language-js">logMe();

var logMe = function() {
  console.log('Logging...');
}</code></pre><p>La ejecución del código se interrumpirá porque con la inicialización de la función, la variable <code>logMe</code> se elevará como una variable, no como una función. Entonces, con el levantamiento de variables, la asignación de memoria ocurrirá con la inicialización con <code>undefined</code>. Esa es la razón por la que obtendremos el error:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-105.png" class="kg-image" alt="image-105" width="600" height="400" loading="lazy"><figcaption>Error en hoisting de la inicialización de una función</figcaption></figure><p>Supongamos que intentamos acceder a una variable antes de la declaración y usamos las palabras clave <code>let</code> y <code>const</code> para declararla más tarde. En ese caso, serán elevados pero no asignados con el <code>undefined</code> predeterminado. Acceder a tales variables resultará en <code>ReferenceError</code>. Aquí hay un ejemplo:</p><pre><code class="language-js">console.log(name);
let name;</code></pre><p>Lanzará el error:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/04/image-106.png" class="kg-image" alt="image-106" width="600" height="400" loading="lazy"><figcaption>Error con hoisting de la variable declarada con las palabras clave let y const</figcaption></figure><p>El mismo código se ejecutará sin problemas si usamos <code>var</code> en lugar de <code>let</code> y <code>const</code>. Este error es un mecanismo de protección del lenguaje JavaScript, como ya hemos comentado, ya que el hoisting accidental puede causar problemas innecesarios.</p><h1 id="antes-de-que-terminemos-"><strong>Antes de que terminemos ..</strong>.</h1><p>Espero que este artículo te haya resultado útil y que te ayude a comprender mejor los conceptos de <code>Contexto de Ejecución</code> y <code>hoisting</code>. </p><p>También te pueden gustar este artículo:</p><ul><li><a href="https://www.freecodecamp.org/espanol/news/la-palabra-clave-this-5-reglas-de-vinculacion-de-teclas-explicadas-para-principiantes-de-javascript/">La palabra clave `this` + 5 reglas de vinculación de teclas (key binding) explicadas para principiantes de JavaScript</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Hoja de trucos React - 9 casos comunes de renderizado HTML que debes conocer ]]>
                </title>
                <description>
                    <![CDATA[ Artículo original escrito por Ondrej Polesny [https://www.freecodecamp.org/news/author/ondrej/] Articulo original: React Cheatsheet – 9 Common HTML Rendering Cases You Should Know [https://www.freecodecamp.org/news/react-cheatsheet-html-rendering/] Traducido y adaptado por: JUAN C. GUAÑA [/espanol/news/author/juancguana/] Cada vez que empiezo con una nueva herramienta o ha pasado un tiempo desde que lo usé, siempre termino buscando las ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/hoja-de-trucos-react-9-casos-comunes-de-renderizado-html-que-debe-conocer/</link>
                <guid isPermaLink="false">6107f21cbd9dff09271bef1a</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan C. Guaña ]]>
                </dc:creator>
                <pubDate>Fri, 13 Aug 2021 02:56:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/08/teaser.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><strong><strong><strong><strong>Artículo original escrito por</strong></strong> </strong></strong><a href="https://www.freecodecamp.org/news/author/ondrej/">Ondrej Polesny</a><br><strong><strong>Articulo original:</strong> </strong><a href="https://www.freecodecamp.org/news/react-cheatsheet-html-rendering/">React Cheatsheet – 9 Common HTML Rendering Cases You Should Know</a><br><strong><strong>Traducido y adaptado por: </strong></strong><a href="https://www.freecodecamp.org/espanol/news/author/juancguana/">JUAN C. GUAÑA</a></p><p>Cada vez que empiezo con una nueva herramienta o ha pasado un tiempo desde que lo usé, siempre termino buscando las mismas cosas simples.</p><p>Buscaré en Google cómo renderizar HTML sin procesar, cómo mostrar un componente en función de una condición, cómo asignar una clase a un elemento, etc.</p><p>Es por eso que creé esta hoja de trucos con las nueve tareas más comunes que realizarás de forma regular con React y <a href="https://reactjs.org/docs/introducing-jsx.html">JSX</a>.</p><p>Los ordené de la forma en que normalmente los encuentro al crear una aplicación. En los ejemplos a continuación, el primer fragmento de código mostrará la sintaxis y el segundo mostrará cómo usarlo con datos reales.</p><h2 id="c-mo-generar-datos-en-html"><strong>Cómo generar datos en HTML</strong></h2><p>El caso de uso más simple de todos: renderizar el valor de una variable en formato HTML. Por lo general, es la primera prueba que muestra que la aplicación ha procesado los datos y puede procesarlos:</p><pre><code class="language-js">{ variable }
</code></pre><pre><code class="language-js">{ metadata.subtitle.value }
</code></pre><h2 id="c-mo-agregar-un-atributo-de-clase-est-ndar"><strong>Cómo agregar un atributo de clase estándar</strong></h2><p>Si bien muchos marcos mantienen intacto el marcado HTML, React no permite que la palabra reservada "clase" se use para diseñar. Necesitamos usar <code>className</code> en su lugar, así:</p><pre><code class="language-js">&lt;... className="classname"&gt;
</code></pre><pre><code class="language-js">&lt;div className="sidebar__inner"&gt;
</code></pre><h2 id="c-mo-generar-datos-en-atributos-html"><strong>Cómo generar datos en atributos HTML</strong></h2><p>Este caso de uso está relacionado con la creación de enlaces. Pero en muchos casos, también necesitas completar atributos como título, datos- {algo-que-tu-aplicación-necesita}, o incluso simples etiquetas alt de imágenes:</p><pre><code class="language-js">&lt; ... name={variable}&gt;
</code></pre><pre><code class="language-js">&lt;a href={`https://twitter.com/${author.twitter.value}`}&gt;
</code></pre><h2 id="c-mo-generar-html-sin-formato"><strong>Cómo generar HTML sin formato</strong></h2><p>Algunos contenidos están estructurados en otro sistema, por ejemplo, texto enriquecido compuesto en un headless CMS.</p><p>En esos casos, normalmente utiliza una herramienta como un SDK para crear el HTML por ti. Así es como puedes agregarlo a su marcado:</p><pre><code class="language-js">&lt; ... dangerouslySetInnerHTML={{__html: variable}}&gt;&lt;/...&gt;
</code></pre><pre><code class="language-js">&lt;div dangerouslySetInnerHTML={{__html: article.teaser}}&gt;&lt;/div&gt;
</code></pre><h2 id="c-mo-iterar-sobre-conjuntos-de-datos"><strong>Cómo iterar sobre conjuntos de datos</strong></h2><p>En páginas de índice, mapas de sitio, páginas de búsqueda o donde sea que necesite mostrar datos de una colección, React y JSX te permiten combinar la función map (casi) todopoderosa con el marcado HTML:</p><pre><code class="language-js">let components = collectionVariable.map((item) =&gt;
  &lt;Component data={item} key={item.uniqueKey} /&gt;);
...
&lt;div&gt;{components}&lt;/div&gt;
</code></pre><pre><code class="language-js">let articleComponents = articles.map((article) =&gt;
  &lt;Article data={article} key={article.id} ... /&gt;);
...
&lt;div&gt;{articleComponents}&lt;/div&gt;
</code></pre><h2 id="c-mo-iterar-sobre-conjuntos-de-datos-con-un-ndice"><strong>Cómo iterar sobre conjuntos de datos con un índice</strong></h2><p>Este es el mismo caso de uso, pero te da acceso a un índice de cada elemento iterado. En algunos casos, el índice también se puede utilizar para reemplazar la clave única:</p><pre><code class="language-js">let components = collectionVariable.map((item, index) =&gt;
  &lt;Component data={item} index={index} key={uniqueKey} /&gt;);
...
&lt;div&gt;{components}&lt;/div&gt;
</code></pre><pre><code class="language-js">let articleComponents = articles.map((article) =&gt;
  &lt;Article data={article} index={index} key={article.id} ... /&gt;);
...
&lt;div&gt;{articleComponents}&lt;/div&gt;
</code></pre><h2 id="c-mo-renderizar-el-marcado-condicional"><strong>Cómo renderizar el marcado condicional</strong></h2><p>Esta es la condición <em>if</em> típica en JSX. A menudo se usa durante la carga de datos para mostrar precargadores o simplemente para decidir qué parte del marcado usar en función de los datos:</p><pre><code class="language-js">{variable !== null &amp;&amp; &lt;... &gt;}
</code></pre><pre><code class="language-js">{data.length &gt; 0 &amp;&amp; &lt;div&gt; ... &lt;/div&gt;}
</code></pre><h2 id="c-mo-renderizar-el-marcado-condicional-incluida-la-rama-else"><strong>Cómo renderizar el marcado condicional, incluida la rama else</strong></h2><p>The else branch is achieved by reversing the condition: La rama else se logra invirtiendo la condición:</p><pre><code class="language-js">{variable !== null &amp;&amp; &lt;... &gt;}
{variable == null &amp;&amp; &lt;... &gt;}
</code></pre><pre><code class="language-js">{data.length &gt; 0 &amp;&amp; &lt;div&gt; ... &lt;/div&gt;}
{data.length == 0 &amp;&amp; &lt;div&gt;Loading...&lt;/div&gt;}
</code></pre><h2 id="c-mo-pasar-datos-a-componentes-secundarios"><strong>Cómo pasar datos a componentes secundarios</strong></h2><p>Y finalmente, cuando comienzas a usar componentes, así es como les proporcionas datos a los children a través de las propiedades:</p><pre><code class="language-js">&lt;component componentVariable={variable}&gt;
</code></pre><pre><code class="language-js">&lt;links author={author}&gt;
</code></pre><p>Espero que esto te ahorre las búsquedas en Google :-)</p><p>Si está buscando una versión imprimible (PDF), está disponible en este<a href="https://ondrabus.com/react-vue-angular-cheatsheet"> sitio</a>, donde también encontrarás hojas de trucos similares para Vue y Angular.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ La hoja de trucos de React Router: todo lo que necesitas saber ]]>
                </title>
                <description>
                    <![CDATA[ Si estás creando aplicaciones React para la web, necesitarás usar un enrutador dedicado para mostrar páginas y navegar por ellas al usuario. Es por eso que hoy vamos a repasar el enrutador más popular y poderoso para aplicaciones React – React Router. Vamos a repasar 11 de las características esenciales ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/la-hoja-de-trucos-de-react-router-todo-lo-que-necesitas-saber/</link>
                <guid isPermaLink="false">60f8142ebc6b3008f09aa52d</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan C. Guaña ]]>
                </dc:creator>
                <pubDate>Mon, 02 Aug 2021 05:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/07/the-react-router-cheatsheet.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Si estás creando aplicaciones React para la web, necesitarás usar un enrutador dedicado para mostrar páginas y navegar por ellas al usuario.</p><p>Es por eso que hoy vamos a repasar el enrutador más popular y poderoso para aplicaciones React – React Router.</p><p>Vamos a repasar 11 de las características esenciales que necesitas saber si estás usando React Router en tus proyectos, específicamente para la web usando el paquete <code>react-router-dom</code>.</p><h2 id="-quieres-tu-propia-copia-"><strong>¿Quieres tu propia copia? <strong>?</strong></strong></h2><p><strong><a href="http://bit.ly/react-router-cheatsheet">Haz clic aquí para descargar la hoja de referencia en formato PDF</a> </strong>(tarda 5 segundos).</p><p>Incluye toda la información esencial como una práctica guía en PDF.</p><h2 id="instala-react-router"><strong>Instala React Router</strong></h2><p>El primer paso para usar React Router es instalar el paquete apropiado.</p><p>Técnicamente, son tres paquetes diferentes: React Router, React Router DOM y React Router Native.</p><p>La principal diferencia entre ellos radica en su uso. React Router DOM es para aplicaciones web y React Router Native es para aplicaciones móviles creadas con React Native.</p><p>Lo primero que deberás hacer es instalar React Router DOM usando npm (o yarn)</p><pre><code class="language-bash">npm install react-router-dom</code></pre><h2 id="configuraci-n-b-sica-de-react-router"><strong>Configuración básica de React Router</strong></h2><p>Una vez instalado, podemos traer nuestro primer componente que se requiere para usar React router, que se llama BrowserRouter.</p><p>Ten en cuenta que hay varios tipos de enrutadores que proporciona <code>react-enrutador-dom</code>, además de BrowserRouter, en el que no entraremos. Es una práctica común poner un alias (renombrar) BrowserRoute simplemente como 'Router' cuando se importa.</p><p>Si queremos proporcionar rutas dentro de toda nuestra aplicación, debe estar envuelto alrededor de todo nuestro árbol de componentes. Es por eso que generalmente lo verás envuelto alrededor o dentro del componente principal de la aplicación:</p><pre><code class="language-js">import { BrowserRouter as Router } from 'react-router-dom';

export default function App() {
  return (
    &lt;Router&gt;
      {/* routes go here, as children */}
    &lt;/Router&gt;
  );
}</code></pre><p>Esta es la función principal del BrowserRouter: poder declarar rutas individuales dentro de nuestra aplicación.</p><p>Ten en cuenta que no se puede acceder a ningún dato específico del enrutador fuera del componente Router. Por ejemplo, no podemos acceder a los datos del historial fuera del enrutador (es decir, con el hook <code>useHistory</code>) y no podemos crear una ruta fuera de un componente Router.</p><h2 id="componente-route"><strong>Componente R<strong>oute</strong></strong></h2><p>El siguiente componente es el componente Route.</p><p>Declaramos rutas dentro del componente Router como secundarias. Podemos declarar tantas rutas como queramos y necesitamos proporcionar al menos dos propiedades para cada ruta, <code>path</code> y <code>component</code> (o render):</p><pre><code class="language-js">import { BrowserRouter as Router, Route } from 'react-router-dom';

export default function App() {
  return (
    &lt;Router&gt;
      &lt;Route path="/about" component={About} /&gt;
    &lt;/Router&gt;
  );
}

function About() {
  return &lt;&gt;about&lt;/&gt;   
}</code></pre><p>La propiedad de <code>path</code> especifica en qué ruta de nuestra aplicación se encuentra localizada una ruta determinada.</p><p>Para una página acerca de, por ejemplo, podríamos querer que esa ruta sea accesible en el path '/ about'.</p><p>Las propiedades <code>render</code> o <code>component</code> se utilizan para mostrar un componente específico para nuestra ruta.</p><p>Las propiedades de <code>component</code> solo pueden recibir una referencia a un componente dado, mientras que <code>render</code> se usa más típicamente para aplicar alguna lógica condicional para renderizar un componente u otro. Para renderizar, puede usar una referencia a un componente o usar una función:</p><pre><code class="language-js">import { BrowserRouter as Router, Route } from "react-router-dom";

export default function App() {
  return (
    &lt;Router&gt;
      &lt;Route path="/" render={() =&gt; &lt;Home /&gt;} /&gt;
      &lt;Route path="/about" component={About} /&gt;
    &lt;/Router&gt;
  );
}

function Home() {
  return &lt;&gt;home&lt;/&gt;;
}

function About() {
  return &lt;&gt;about&lt;/&gt;;
}</code></pre><p>Vale la pena señalar que potencialmente puedes eliminar el <code>reder</code> o la propiedad <code>component</code> por completo y usar el componente que desea asociar con una ruta determinada como hijo de Route:</p><pre><code class="language-js">import { BrowserRouter as Router, Route } from "react-router-dom";

export default function App() {
  return (
    &lt;Router&gt;
      &lt;Route path="/about"&gt;
        &lt;About /&gt;
      &lt;/Route&gt;
    &lt;/Router&gt;
  );
}</code></pre><p>Finalmente, si deseas que un componente (como una barra de navegación) sea visible en todas las páginas, colóquelo dentro del <code>BrowseRouter</code>, pero arriba (o debajo) de las rutas declaradas:</p><pre><code class="language-js">import { BrowserRouter as Router, Route } from "react-router-dom";

export default function App() {
  return (
    &lt;Router&gt;
      &lt;Navbar /&gt;
      &lt;Route path="/" component={Home} /&gt;
      &lt;Route path="/about" component={About} /&gt;
    &lt;/Router&gt;
  );
}

function Navbar() {
  // visible on every page
  return &lt;&gt;navbar&lt;/&gt;
}

function Home() {
  return &lt;&gt;home&lt;/&gt;;
}

function About() {
  return &lt;&gt;about&lt;/&gt;;
}</code></pre><h2 id="componente-switch"><strong>Componente s<strong>witch</strong></strong></h2><p>Cuando comencemos a agregar múltiples rutas, notaremos algo extraño.</p><p>Digamos que tenemos una ruta para la página de inicio y la página acerca de. Aunque especificamos dos rutas diferentes, '/' y '/about', cuando visito la página acerca de, veremos los componentes de inicio y acerca de.</p><p>Podemos arreglar esto con la propiedad exact, en la ruta de inicio para asegurarnos de que nuestro enrutador coincida exactamente con la ruta '/' en lugar de '/about':</p><pre><code class="language-js">import { BrowserRouter as Router, Switch, Route } from "react-router-dom";

export default function App() {
  return (
    &lt;Router&gt;
      &lt;Navbar /&gt;
      &lt;Switch&gt;
        &lt;Route exact path="/" component={Home} /&gt;
        &lt;Route path="/about" component={About} /&gt;
      &lt;/Switch&gt;
    &lt;/Router&gt;
  );
}</code></pre><p>Cuando se trata de cambiar entre diferentes rutas que nuestro enrutador debería mostrar, de hecho hay un componente dedicado que debe usar si tiene múltiples rutas dentro de su enrutador y ese es el componente Switch.</p><p>El componente switch debe incluirse dentro del componente Router y podemos colocar todas nuestras rutas dentro de él:</p><pre><code class="language-js">import { BrowserRouter as Router, Switch, Route } from "react-router-dom";

export default function App() {
  return (
    &lt;Router&gt;
      &lt;Navbar /&gt;
      &lt;Switch&gt;
        &lt;Route exact path="/" component={Home} /&gt;
        &lt;Route path="/about" component={About} /&gt;
      &lt;/Switch&gt;
    &lt;/Router&gt;
  );
}</code></pre><p>El componente switch examina todas sus rutas secundarias y muestra la primera cuya ruta coincide con la URL actual.</p><p>Este componente es el que queremos usar en la mayoría de los casos para la mayoría de las aplicaciones, porque tenemos múltiples rutas y múltiples páginas en nuestra aplicación, pero solo queremos mostrar una página a la vez.</p><p>Si por alguna razón deseas que se muestren varias páginas al mismo tiempo, puedes considerar no usar el componente switch.</p><h2 id="ruta-404"><strong>Ruta <strong>404</strong></strong></h2><p>Si intentamos ir a una ruta que no existe en nuestra aplicación, ¿qué vamos a ver?</p><p>No vamos a ver nada si no tenemos una ruta correspondiente. ¿Cómo hacemos una ruta global?</p><p>Si un usuario intenta ir a una página para la que no tenemos una ruta definida, podemos crear una ruta y luego establecer la ruta con un asterisco *:</p><pre><code class="language-js">import { BrowserRouter as Router, Switch, Route } from "react-router-dom";

export default function App() {
  return (
    &lt;Router&gt;
      &lt;Navbar /&gt;
      &lt;Switch&gt;
        &lt;Route path="/" component={Home} /&gt;
        &lt;Route path="/about" component={About} /&gt;
        &lt;Route path="*" component={NotFound} /&gt;
      &lt;/Switch&gt;
    &lt;/Router&gt;
  );
}

function NotFound() {
  return &lt;&gt;Ha llegado a una página que no existe&lt;/&gt;;
}</code></pre><p>Esto coincidirá con cualquier intento de visitar una página que no existe y podemos conectarlo a un componente no encontrado para decirles a nuestros usuarios que han "Llegado a una página que no existe".</p><h2 id="componente-link"><strong>Componente <strong>Link</strong></strong></h2><p>Digamos que dentro de nuestra barra de navegación, en realidad queremos crear algunos enlaces para poder movernos por nuestra aplicación más fácilmente en lugar de tener que cambiar la URL manualmente en el navegador.</p><p>Podemos hacerlo con otro componente especial de React Router DOM llamado componente Link. Acepta la propiedad <code>to</code>, que especifica a dónde queremos que el enlace navegue nuestro usuario. En nuestro caso, podríamos tener un enlace de inicio y acerca de:</p><pre><code class="language-js">import { BrowserRouter as Router, Switch, Route, Link } from "react-router-dom";

export default function App() {
  return (
    &lt;Router&gt;
      &lt;Navbar /&gt;
      &lt;Switch&gt;
        &lt;Route path="/" component={Home} /&gt;
        &lt;Route path="/about" component={About} /&gt;
      &lt;/Switch&gt;
    &lt;/Router&gt;
  );
}

function Navbar() {
  return (
    &lt;nav&gt;
      &lt;Link to="/"&gt;Home&lt;/Link&gt;
      &lt;Link to="/about"&gt;About&lt;/Link&gt;
    &lt;/nav&gt;
  )
}</code></pre><p>El componente Link nos permite proporcionar algunos estilos en línea como cualquier componente estándar de React. También nos brinda una propiedad útil para el componente, por lo que podemos configurar nuestro enlace como nuestro propio componente personalizado para un estilo aún más fácil.</p><h2 id="componente-navlink"><strong>Componente <strong>NavLink</strong></strong></h2><p>Además, React Router DOM nos proporciona el componente NavLink que es útil en caso de que queramos aplicar algunos estilos especiales.</p><p>Si estamos en la ruta actual a la que apunta el enlace, esto nos permite crear algunos estilos de enlaces activos para decirles a nuestros usuarios, al mirar nuestro enlace, en qué página se encuentran.</p><p>Por ejemplo, si nuestros usuarios están en la página de inicio, podríamos decirles lo mismo usando el accesorio <code>activeStyle</code> para hacer que nuestro enlace esté en negrita y rojo cuando estén en la página de inicio:</p><pre><code class="language-js">import {
  BrowserRouter as Router,
  Switch,
  Route,
  NavLink
} from "react-router-dom";

export default function App() {
  return (
    &lt;Router&gt;
      &lt;Navbar /&gt;
      &lt;Switch&gt;
        &lt;Route path="/" component={Home} /&gt;
        &lt;Route path="/about" component={About} /&gt;
      &lt;/Switch&gt;
    &lt;/Router&gt;
  );
}

function Navbar() {
  return (
    &lt;nav&gt;
      &lt;NavLink
        activeStyle={{
          fontWeight: "bold",
          color: "red"
        }}
        to="/"
      &gt;
        Home
      &lt;/NavLink&gt;
      &lt;NavLink activeClassName="active" to="/about"&gt;
        About
      &lt;/NavLink&gt;
    &lt;/nav&gt;
  );
}
</code></pre><p>También hay una propiedad <code>activeClassName</code> que también se puede configurar si no deseas incluir estilos en línea o deseas más estilos reutilizables para realizar la misma función que <code>activeStyle</code>.</p><h2 id="componente-redirect"><strong>Componente <strong>Redirect</strong></strong></h2><p>Otro componente muy útil que nos da React Router DOM es el componente de redireccionamiento.</p><p>Puede parecer extraño tener un componente que realice la función de redirigir a nuestro usuario cuando se muestra, pero esto es muy funcional.</p><p>Siempre que usemos algo como una ruta privada y tengamos una condición en la que el usuario no esté autenticado, queremos redirigirlo a la página de inicio de sesión.</p><p>A continuación, se muestra un ejemplo de una implementación de un componente de ruta privada que garantiza que un usuario esté autenticado antes de mostrarle una ruta en particular que ha sido declarada con este componente.</p><p>De lo contrario, si no están autenticados, serán redirigidos a una ruta pública (presumiblemente una ruta para iniciar sesión) una vez que se muestre el componente de redireccionamiento:</p><pre><code class="language-js">import {
  BrowserRouter as Router,
  Switch,
  Route,
  Redirect
} from "react-router-dom";

export default function App() {
  return (
    &lt;Router&gt;
      &lt;Switch&gt;
        &lt;Route exact path="/" component={Home} /&gt;
        &lt;PrivateRoute path="/hidden" component={Hidden} /&gt;
      &lt;/Switch&gt;
    &lt;/Router&gt;
  );
}

function PrivateRoute({ component: Component, ...rest }) {
  // useAuth es un hook personalizado para obtener el estado de autenticación del usuario actual
  const isAuth = useAuth();

  return (
    &lt;Route
      {...rest}
      render={(props) =&gt;
        isAuth ? &lt;Component {...props} /&gt; : &lt;Redirect to="/" /&gt;
      }
    /&gt;
  );
}

function Home() {
  return &lt;&gt;home&lt;/&gt;;
}

function Hidden() {
  return &lt;&gt;hidden&lt;/&gt;;
}</code></pre><p>El componente Redirect es muy simple de usar, muy declarativo y nos permite ver el gran beneficio de que React Router DOM esté basado en componentes, como todo en React.</p><h2 id="hook-usehistory"><strong><strong>Hook</strong> <strong>useHistory </strong></strong></h2><p>Además de todos estos poderosos componentes, hay algunos hooks muy útiles que React Router DOM nos brinda.</p><p>Son útiles principalmente al proporcionar información adicional que podemos utilizar dentro de nuestros componentes. Se pueden llamar como hooks de React normales para los que podemos usar sus valores exactamente como queramos.</p><p>Perhaps the most powerful hook is the <code>useHistory</code> hook. We can call it up at the top of any component that is declared within our router component and get back <code>history</code> data, which includes information such as the location associated with our component. Quizás el hook más poderoso es el hook <code>useHistory</code>. Podemos llamarlo en la parte superior de cualquier componente que se declare dentro de nuestro componente de Router y recuperar los datos de <code>history</code>, que incluyen información como la ubicación asociada con nuestro componente.</p><p>Este nos dice todo acerca de dónde se encuentra actualmente el usuario, como el nombre de la ruta en la que se encuentra, así como cualquier parámetro de consulta que pueda agregarse a nuestra URL. Se puede acceder a todos los datos de ubicación desde <code>history.location</code>:</p><pre><code class="language-js">import { useHistory } from "react-router-dom";


function About() {
  const history = useHistory();
    
  console.log(history.location.pathname); // '/about'

  return (
    &lt;&gt;
     &lt;h1&gt;La página about esta en: {history.location.pathname}&lt;/h1&gt;
    &lt;/&gt;
  );
}</code></pre><p>Además, el objeto history incluye directamente métodos útiles que nos permiten dirigir mediante programación a nuestro usuario a diferentes páginas de nuestra aplicación.</p><p>Esto es muy útil, por ejemplo, para redirigir a nuestro usuario después de iniciar sesión, o en cualquier situación en la que necesitemos llevar a un usuario de una página a otra.</p><p>Podemos empujar a los usuarios de una página a otra usando <code>history.push</code>. Cuando usamos el método push, solo necesitamos proporcionar la ruta que queremos llevar a nuestros usuarios a usar este método. Agrega esta nueva página a la pila (por así decirlo) de nuestro history:</p><pre><code class="language-js">import { useHistory } from "react-router-dom";


function About() {
  const history = useHistory();
    
  console.log(history.location.pathname); // '/about'

  return (
    &lt;&gt;
     &lt;h1&gt;The about page is on: {history.location.pathname}&lt;/h1&gt;
     &lt;button onClick={() =&gt; history.push('/')}&gt;Go to home page&lt;/button&gt;
    &lt;/&gt;
  );
}</code></pre><p>También podemos redirigir a nuestros usuarios con <code>history.replace</code>, que también acepta un valor de ruta, pero borra todo en el historial, después de que se realiza la navegación. Esto es útil para situaciones en las que ya no es necesario retroceder en el historial, como después de que los usuarios hayan cerrado la sesión.</p><h2 id="hook-uselocation"><strong><strong>Hook</strong> <strong>useLocation </strong></strong></h2><p>El hook <code>useLocation</code> incluye toda la misma información que el hook <code>useHistory</code>.</p><p>Es importante tener en cuenta que si necesita tantos datos de ubicación cómo usar el historial para navegar programáticamente por su usuario, asegúrese de usar <code>useHistory</code>. Sin embargo, si solo desea datos de ubicación, todo lo que necesita hacer es llamar a <code>useLocation</code> o recuperar todos los datos de ubicación en un objeto que sea idéntico a los datos proporcionados en el <code>history.location</code>:</p><pre><code class="language-js">import { useLocation } from "react-router-dom";


function About() {
  const location = useLocation();
    
  console.log(location.pathname); // '/about'

  return (
    &lt;&gt;
     &lt;h1&gt;La página about esta en: {location.pathname}&lt;/h1&gt;
    &lt;/&gt;
  );
}</code></pre><h2 id="hook-useparams-rutas-din-micas"><strong><strong>Hook</strong> <strong>useParams &nbsp;+ </strong>Rutas dinámicas</strong></h2><p>Una cosa que no cubrimos cuando se trata de rutas es que naturalmente podemos crear rutas dinámicas. Esto significa rutas que no son fijas y determinadas, pero que pueden tener cualquier número de caracteres.</p><p>Las rutas dinámicas son útiles en situaciones en las que tenemos, digamos, una publicación de blog con un slug o identificador único. ¿Cómo nos aseguramos de mostrar los datos adecuados y los componentes adecuados, dado que el slug de nuestra publicación en el blog puede ser completamente diferente?</p><p>Para declarar un parámetro de ruta en una ruta determinada, este debe ir precedido de dos puntos <code>:</code>. Si queremos crear una ruta dinámica, "/ blog /: postSlug", para un componente de publicación de blog, podría verse así:</p><pre><code class="language-js">import React from "react";
import { BrowserRouter as Router, Switch, Route } from "react-router-dom";

export default function App() {
  return (
    &lt;Router&gt;
      &lt;Switch&gt;
        &lt;Route exact path="/" component={Home} /&gt;
        &lt;Route path="/blog/:postSlug" component={BlogPost} /&gt;
      &lt;/Switch&gt;
    &lt;/Router&gt;
  );
}

function Home() {
  return &lt;&gt;home&lt;/&gt;;
}

function BlogPost() {
  return &lt;&gt;blog post&lt;/&gt;;
}
</code></pre><p>Ahora estamos haciendo coincidir el componente apropiado o lo que sea el slug o identificador único. Pero dentro de nuestro componente BlogPost, ¿cómo recibimos los datos de esa publicación?</p><p>Podemos acceder a cualquier parámetro de ruta de una ruta declarada con su componente asociado usando el hook <code>useParams</code>.</p><p>useParams devolverá un objeto que contendrá propiedades que coincidan con nuestros parámetros de ruta (en este caso, <code>postSlug</code>). Podemos usar la desestructuración de objetos para acceder inmediatamente y declarar como una variable con el nombre <code>postSlug</code>:</p><pre><code class="language-js">import React from "react";
import { BrowserRouter as Router, Switch, Route, useParams } from "react-router-dom";

export default function App() {
  return (
    &lt;Router&gt;
      &lt;Switch&gt;
        &lt;Route exact path="/" component={Home} /&gt;
        &lt;Route path="/blog/:postSlug" component={BlogPost} /&gt;
      &lt;/Switch&gt;
    &lt;/Router&gt;
  );
}

function Home() {
  return &lt;&gt;home&lt;/&gt;;
}

function BlogPost() {
  const [post, setPost] = React.useState(null);
  const { postSlug } = useParams();

  React.useEffect(() =&gt; {
    fetch(`https://jsonplaceholder.typicode.com/posts/${postSlug}`)
      .then((res) =&gt; res.json())
      .then((data) =&gt; setPost(data));
  }, [postSlug]);

  if (!post) return null;

  return (
    &lt;&gt;
      &lt;h1&gt;{post.title}&lt;/h1&gt;
      &lt;p&gt;{post.description}&lt;/p&gt;
    &lt;/&gt;
  );
}</code></pre><p>Si vamos a la ruta '/blog/my-blog-post', puedo acceder a la cadena 'my-blog-post' en la variable <code>postSlug</code> y recuperar los datos asociados a esa publicación dentro de useEffect.</p><h2 id="useroutematch-hook"><strong><strong>useRouteMatch Hook</strong></strong></h2><p>Si queremos saber si el componente dado está en una página determinada, podemos usar el hook <code>useRouteMatch</code>.</p><p>Por ejemplo, dentro de nuestra publicación de blog, para ver si la página en la que estamos coincide con la ruta "/blog/:postSlug", podemos recuperar un valor booleano que nos dirá si la ruta en la que estamos coincide con el patrón que especificamos:</p><pre><code class="language-js">import { useRouteMatch } from "react-router-dom";

function BlogPost() {
  const isBlogPostRoute = useRouteMatch("/blog/:postSlug");
 
  // mostrar, ocultar contenido o hacer otra cosa
}</code></pre><p>Esto es útil en condiciones en las que queremos mostrar algo específico, en función de si estamos en una ruta determinada o no.</p><h2 id="-quiere-conservar-esta-gu-a-para-futuras-consultas"><strong>¿Quiere conservar esta guía para futuras consultas?</strong></h2><p><strong><a href="http://bit.ly/react-router-cheatsheet">Haz clic aquí para descargar la hoja de referencia en formato PDF</a></strong></p><p>Aquí hay 3 ganancias rápidas que obtiene cuando obtiene la versión descargable:</p><ul><li>Obtendrás toneladas de fragmentos de código copiables para reutilizarlos fácilmente en sus propios proyectos.</li><li>Es una excelente guía de referencia para fortalecer sus habilidades como desarrollador de React y para entrevistas de trabajo.</li><li> Puede tomar, usar, imprimir, leer y releer esta guía literalmente en cualquier lugar que desees.</li></ul><p>Traducido del artículo de<strong><strong><strong><strong> <a href="https://www.freecodecamp.org/news/author/reed/">Reed Barger</a> - </strong></strong></strong><a href="https://www.freecodecamp.org/news/react-router-cheatsheet/">The React Router Cheatsheet – Everything You Need to Know</a></strong></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Lo que todo desarrollador de React debe saber sobre el estado ]]>
                </title>
                <description>
                    <![CDATA[ Uno de los conceptos más importantes que todo desarrollador de React debe comprender es el estado: qué es, cómo usarlo correctamente y cómo evitar los errores comunes a medida que construye sus aplicaciones. Vamos a cubrir cinco de las partes más esenciales del estado que necesitas saber. Cada una de ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/lo-que-todo-desarrollador-de-react-debe-saber-sobre-el-estado/</link>
                <guid isPermaLink="false">60e5e283ce2597091235ee5f</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan C. Guaña ]]>
                </dc:creator>
                <pubDate>Fri, 30 Jul 2021 10:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/07/5-things-every-react-developer-should-know-about-state.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Uno de los conceptos más importantes que todo desarrollador de React debe comprender es el estado: qué es, cómo usarlo correctamente y cómo evitar los errores comunes a medida que construye sus aplicaciones.</p><p>Vamos a cubrir cinco de las partes más esenciales del estado que necesitas saber. Cada una de estas partes se basa en la otra para ayudarte a comprender en general un tema algo complejo.</p><p>Para que estos conceptos abstractos sean lo más claros posible, he incluido muchos ejemplos prácticos que puede ejecutar en Code Sandbox o en cualquier proyecto de React que hayas configurado.</p><h2 id="1-las-actualizaciones-de-estado-con-usestate-no-se-combinan"><strong><strong>1. </strong>Las actualizaciones de estado con useState no se combinan</strong></h2><p>Un desafío al que se enfrentan muchos desarrolladores de React al pasar de componentes basados ​​en clases a componentes de funciones con hooks de React es que las actualizaciones de estado que utilizan objetos ya no se fusionan automáticamente.</p><p>Una gran ventaja del hook useState es que podemos llamarlo tantas veces como queramos para usar tantas variables de estado como necesitemos.</p><p>En este ejemplo, tenemos un formulario básico con una entrada de correo electrónico y contraseña. Gestionamos el estado del correo electrónico y la contraseña como variables de estado individuales:</p><pre><code class="language-js">import React from "react";

export default function App() {
  const [email, setEmail] = React.useState("");
  const [password, setPassword] = React.useState("");

  return (
    &lt;form&gt;
      &lt;input
        name="email"
        type="email"
        placeholder="Email"
        onChange={(e) =&gt; setEmail(e.target.value)}
      /&gt;
      &lt;input
        name="password"
        type="password"
        placeholder="Password"
        onChange={(e) =&gt; setPassword(e.target.value)}
      /&gt;
      &lt;button type="submit"&gt;Submit&lt;/button&gt;
    &lt;/form&gt;
  );
}</code></pre><p>Cambiemos nuestro ejemplo para administrar nuestro estado de formulario dentro de un solo objeto. Esto nos permite llamar a useState solo una vez, donde el correo electrónico y la contraseña no son administrados por variables de estado individuales sino como propiedades de esta variable de estado llamada <code>state</code>.</p><p><em>¿Cómo actualizamos adecuadamente el estado con la función <code>setState</code> cuando es un objeto?</em></p><p>Si usáramos un controlador de eventos genérico que está conectado a la propiedad <code>onChange</code> de cada una de las entradas de nuestro formulario, se vería así:</p><pre><code class="language-js">import React from "react";

export default function App() {
  const [state, setState] = React.useState({
    email: '',
    password: ''
  })

  function handleInputChange(e) {
    setState({
      [e.target.name]: e.target.value
    })
  }

  return (
    &lt;form&gt;
      &lt;input
        name="email"
        type="email"
        onChange={handleInputChange}
      /&gt;
      &lt;input
        name="password"
        type="password"
        onChange={handleInputChange}
      /&gt;
      &lt;button type="submit"&gt;Submit&lt;/button&gt;
    &lt;/form&gt;
  );
}</code></pre><p>Ahora estamos actualizando el valor de cada entrada en estado de acuerdo con el nombre de la entrada que nuestro usuario está escribiendo actualmente.</p><p>Este patrón se usa comúnmente para actualizar el estado en componentes basados ​​en clases, pero esto no funciona con el hook <code>useState</code>. Las actualizaciones de estado con la función setState de useState no se combinan automáticamente.</p><p><em>¿Qué significa eso?</em></p><p>Significa que siempre que establecemos el estado a medida que nuestro usuario escribe, el estado anterior no se incluye en el nuevo estado. Si tuviéramos que registrar nuestro estado recién actualizado mientras escribimos en nuestro formulario, vemos lo siguiente:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/5-things-every-react-developer-should-know-about-state-1.gif" class="kg-image" alt="5-things-every-react-developer-should-know-about-state-1" width="600" height="400" loading="lazy"></figure><p>Dado que el estado anterior no se fusiona automáticamente con el nuevo objeto de estado, debemos fusionar manualmente nuestro objeto de estado con sus propiedades anteriores utilizando el operador de propagación del objeto:</p><pre><code class="language-js">import React from "react";

export default function App() {
  const [state, setState] = React.useState({
    email: '',
    password: ''
  })

  function handleInputChange(e) {
    setState({
      // spread in previous state with object spread operator
      ...state,
      [e.target.name]: e.target.value
    })
  }

  return (
    &lt;form&gt;
      &lt;input
        name="email"
        type="email"
        onChange={handleInputChange}
      /&gt;
      &lt;input
        name="password"
        type="password"
        onChange={handleInputChange}
      /&gt;
      &lt;button type="submit"&gt;Submit&lt;/button&gt;
    &lt;/form&gt;
  );
}</code></pre><p>Para el hook useState, tenemos la flexibilidad de administrar múltiples valores primitivos o usar un objeto con múltiples propiedades.</p><p>Sin embargo, si usas useState con un objeto, recuerda propagar en el estado anterior cuando se realice cualquier actualización para asegurarse de que se actualice correctamente.</p><h2 id="2-los-hooks-de-estado-desencadenan-una-re-renderizaci-n-useref-no"><strong><strong>2. </strong>Los hooks de estado desencadenan una re-renderización, useRef no</strong></h2><p>El estado de reacción tiene una relación muy importante con los componentes de renderizado.</p><p>Siempre que devolvemos JSX desde un componente de React, cuando se usa ese componente, se renderizará y, por lo tanto, se mostrará en nuestra aplicación. React se encarga de este proceso de renderizado.</p><p>Si nuestro componente usa cualquier estado, debemos entender que debe re-renderizarse, es decir, volver a renderizar, en respuesta a cualquier actualización de estado.</p><p><em>¿Por qué es necesario volver a renderizar los componentes en las actualizaciones de estado?</em></p><p>Porque si no volvemos a renderizar al actualizar el estado, no podríamos mostrar nuevos datos. Esto se expresa de manera muy simple, siempre que mostramos cualquier estado contenido dentro de una variable de estado dentro de nuestro JSX.</p><p>Si no se volviera a renderizar cada vez que realizamos cambios en esa variable, las actualizaciones no se mostrarían.</p><p>Esto parece un concepto bastante simple, pero debes comprender que <strong>cada vez que actualizamos el estado, no solo provoca una nueva renderización en el componente que administra directamente el estado, sino que también provoca una nueva renderización en todos los componentes secundarios.</strong></p><p><em>¿Por qué es importante esto?</em> Porque en algunos casos, es posible que no queramos que un componente secundario se vuelva a renderizar en respuesta a una nueva representación del componente principal.</p><p><em>¿Cuál es uno de esos ejemplos?</em> Digamos que tenemos una aplicación en la que un usuario puede escribir en una entrada cuyo valor se administra a través del estado. Esta aplicación también tiene otro componente que muestra una lista de datos.</p><p>Siempre que el usuario escribe en la entrada, nuestro estado se actualiza y esto provoca una re-renderización innecesaria en ese otro componente hijo.</p><p>La forma en que podemos solucionar esto es con la ayuda de la función <code>React.memo</code>, que ayuda a evitar que nuestro componente se vuelva a renderizar cuando un componente padre se vuelve a renderizar:</p><pre><code class="language-js">export default function App() {
  const [skill, setSkill] = React.useState("");
  const [skills, setSkills] = React.useState(["HTML", "CSS", "JavaScript"]);

  function handleChangeInput(event) {
    setSkill(event.target.value);
  }

  function handleAddSkill() {
    setSkills(skills.concat(skill));
  }

  return (
    &lt;&gt;
      &lt;input onChange={handleChangeInput} /&gt;
      &lt;button onClick={handleAddSkill}&gt;Add Skill&lt;/button&gt;
      &lt;SkillList skills={skills} /&gt;
    &lt;/&gt;
  );
}

/* Pero el problema, si ejecutas este código tu mismo, es que cuando escribimos en la entrada, debido a que el componente principal de SkillList (App) vuelve a renderizarse, debido a que el estado se actualiza con cada pulsación de tecla, SkillList se vuelve a renderizar constantemente (como lo indicada console.log) */

/* Sin embargo, una vez que envolvemos el componente SkillList en React.memo (que es una función de orden superior, lo que significa que acepta una función como argumento), ya no se vuelve a renderizar innecesariamente cuando lo hace nuestro componente padre. */
const SkillList = React.memo(({ skills }) =&gt; {
  console.log("rerendering");
  return (
    &lt;ul&gt;
      {skills.map((skill, i) =&gt; (
        &lt;li key={i}&gt;{skill}&lt;/li&gt;
      ))}
    &lt;/ul&gt;
  );
});</code></pre><p>Otra cosa a tener en cuenta aquí es que técnicamente hay una forma de administrar el estado sin causar una nueva renderización. Podemos hacerlo con un hook que la mayoría de la gente no ve como un gancho de React con estado: <code>useRef</code>.</p><p>useRef se puede utilizar para almacenar cualquier valor en su propiedad <code>.current</code>. En otras palabras, si quisiéramos hacer un contador simple con useRef y actualizar un valor de recuento que almacenamos en él, incluso si actualizamos su valor, no mostraría el recuento correcto después del render inicial porque hacerlo no activa un re-render:</p><pre><code class="language-js">import React from "react";

export default function App() {
  const countRef = React.useRef(0);

  function handleAddOne() {
    countRef.current += 1;
  }

  return (
    &lt;&gt;
      &lt;h1&gt;Count: {countRef.current}&lt;/h1&gt;

      {/* clicking this will not change display count */}
      &lt;button onClick={handleAddOne}&gt;+ 1&lt;/button&gt;
    &lt;/&gt;
  );
}</code></pre><h2 id="3-las-actualizaciones-de-estado-deben-ser-inmutables"><strong><strong>3. </strong>Las actualizaciones de estado deben ser inmutables</strong></h2><p>Una parte muy importante del estado en React es que debe actualizarse y administrarse de la manera correcta.</p><p>Cuando se trata de administrar el estado con el hook useState, debemos usar <em>solo </em>la función de useState dedicado a modificar el estado y se proporciona como el segundo elemento en el arreglo que obtenemos de useState para actualizarlo. Si no lo hacemos e intentamos actualizarlo manualmente, por ejemplo, con la ayuda de JavaScript plano nuestra aplicación no funcionará como esperamos.</p><p>Este punto está muy relacionado con el punto anterior que hicimos: el estado, cuando se actualiza <em>correctamente</em>, provoca una re-renderización de nuestro componente.</p><p>¿Qué crees que pasará si intentamos actualizar el estado a nuestra manera en lugar de "React"?</p><p>Una vez más, React es el que se encarga de mostrar y renderizar nuestro componente correctamente cuando algo cambia. Si no usamos React, entonces no podemos esperar que nuestra aplicación refleje los cambios que hicimos en el estado.</p><p>En otras palabras, <strong>si actualizamos el estado con JavaScript plano y no <code>setState</code></strong>, no activará una nueva renderización y React no mostrará esos cambios (inválidos) en el estado a nuestro usuario.</p><p>Esta es una lección simple pero crucial para recordar.</p><p>Debemos saber cómo actualizar el estado usando React y elegir el hook de estado apropiado para nuestros propósitos. Podríamos elegir <code>useReducer</code>, <code>useState</code> o una biblioteca de administración de estado de terceros como Redux.</p><p>Independientemente de nuestra elección en la gestión del estado, debemos actualizar el estado de la manera adecuada y no intentar actualizarlo o modificarlo directamente.</p><p>La otra razón de esto, además de que nuestra aplicación React no funciona correctamente, es que viola un principio básico de React. Este es el concepto de <strong>inmutabilidad</strong>.</p><p>Las actualizaciones de estado siempre deben ser inmutables. Esto significa que no deberíamos hacer nuestros propios cambios o mutar los datos almacenados en nuestras variables de estado. Hacerlo hace que nuestro estado sea impredecible y puede causar problemas no deseados en nuestra aplicación que son difíciles de depurar.</p><pre><code class="language-js">import React from 'react';

export default function App() {
  const [count, setCount] = React.useState(0);
  
  // No asigne estado a nuevas variables (que no usen el hook useState)
  const newCount = count;
  // No mutes directamente el estado
  const countPlusOne = count + 1;

  return (
    &lt;&gt;
      &lt;h1&gt;Count: {count}&lt;/h1&gt;
    &lt;/&gt;
  );
}</code></pre><p>Además de no mutar las variables de estado directamente, asegúrese de no asignar nunca variables de estado a otras variables (que no usen el hook useState).</p><h2 id="4-las-actualizaciones-de-estado-son-asincr-nicas-y-programadas"><strong><strong>4. </strong>Las actualizaciones de estado son asincrónicas y programadas</strong></h2><p>Una lección crucial que debe saber sobre las actualizaciones del estado es que no se realizan de inmediato.</p><p>Esto se puede ver si echamos un vistazo a la documentación de React y vemos exactamente qué sucede cuando llamamos a la función <code>setState</code>. Lo usamos para actualizar la variable de estado asociada con él, pero también se nos dice:</p><blockquote>Acepta un nuevo valor de estado y pone en cola (<em><em>enqueues</em></em>) una reproducción del componente.</blockquote><p><em>¿Qué significa esta palabra "<em>enqueues</em>"?</em></p><p>En otras palabras, no vuelve a renderizar el componente inmediatamente. No detiene nuestro código justo en esa línea donde actualizamos el estado, pero tiene lugar en algún momento en el futuro. Esto es por motivos de rendimiento y esto nos da una mejor idea de lo que React está haciendo bajo el capó.</p><p>Basándonos en esta información, necesitamos cambiar nuestro modelo mental cuando intentamos actualizar el estado: <strong>la función <code>setState</code> no actualiza inmediatamente el estado, simplemente programa una actualización de estado para algún tiempo en el futuro</strong>. Después de lo cual, React se encarga de averiguar cuándo se lleva a cabo esa actualización de estado.</p><p>Por lo tanto, no es tan fácil poder mirar nuestro código y ver exactamente cuándo ocurrió o ocurrirá la actualización de estado.</p><p>Es importante comparar esto con <code>useRef</code>, que mencionamos anteriormente como capaz de retener los datos dentro de su propiedad actual. Cualquier actualización realizada con useRef se realiza de forma sincrónica; podemos mirar nuestro código y ver exactamente cuándo se realizó una actualización determinada en <code>useRef</code>, pero no con useState.</p><h2 id="5-el-estado-obsoleto-puede-ocurrir-con-los-closures"><strong><strong>5. </strong>El estado obsoleto puede ocurrir con los closures</strong></h2><p>Finalmente, un problema importante que puede ocurrir con el estado React es el problema del estado obsoleto.</p><h3 id="-qu-es-el-estado-obsoleto-en-react">¿Qué es el estado obsoleto en React?</h3><p>El estado obsoleto es un problema que ocurre cada vez que intentamos actualizar el estado, a menudo dentro de un closure.</p><blockquote>Un closure es un tipo de función en JavaScript, donde usamos una variable de un ámbito externo.</blockquote><p>Este problema del estado obsoleto se basa en el hecho de que el cierre podría no capturar el valor de la variable de estado más actualizado. Eso es lo que queremos decir con obsoleto: queremos decir que es antiguo y no el valor actual que queremos.</p><p>Este problema de estado obsoleto está estrechamente relacionado con el tema que discutimos anteriormente de las actualizaciones de estado son asincrónicas.</p><p>En muchos casos, el problema de que las actualizaciones de estado sean asincrónicas es que no siempre obtenemos el valor anterior correcto de nuestro estado, especialmente si intentamos actualizar el estado en función de ese valor anterior.</p><p>Podemos expresar el problema de un closure obsoleto dentro de una aplicación de contador simple que actualiza el recuento después de un segundo usando la función <code>setTimeout</code>.</p><p>Debido a que setTimeout crea un closure, estamos accediendo a un valor obsoleto de nuestra variable de estado, <code>count</code>, cuando llamamos a <code>setCount</code>.</p><pre><code class="language-js">import React from 'react';

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

  function delayAddOne() {
    setTimeout(() =&gt; {
      setCount(count + 1);
    }, 1000);
  }

  return (
    &lt;&gt;
      &lt;h1&gt;Count: {count}&lt;/h1&gt;
      &lt;button onClick={delayAddOne}&gt;+ 1&lt;/button&gt;
    &lt;/&gt;
  );
}</code></pre><p>El problema es evidente cuando ejecutamos nuestra aplicación. A pesar de hacer clic en el botón varias veces, solo se incrementa en uno por segundo:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/5-thing-every-react-developer-should-know-about-state-2.gif" class="kg-image" alt="5-thing-every-react-developer-should-know-about-state-2" width="600" height="400" loading="lazy"></figure><p>Podemos solucionar este problema de nuestro estado obsoleto dentro de nuestro closure utilizando un método más confiable para actualizar el estado. Las actualizaciones de estado todavía se van a programar, pero permitirán obtener de forma fiable el valor de estado anterior.</p><p>Hacemos esto con la ayuda de proporcionar una función interna a la función <code>setState</code>. En el cuerpo de la función, podemos obtener el estado anterior dentro de los parámetros de esta función y luego devolver lo que queremos que sea el siguiente estado.</p><p>En nuestro caso, será el valor de recuento anterior incrementado en uno:</p><pre><code class="language-js">import React from 'react';

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

  function delayAddOne() {
    setTimeout(() =&gt; {
      // El problema del estado obsoleto desaparece usando una función interna
      setCount(prevCount =&gt; prevCount + 1);
    }, 1000);
  }

  return (
    &lt;div&gt;
      &lt;h1&gt;Count: {count}&lt;/h1&gt;
      &lt;button onClick={delayAddOne}&gt;+ 1&lt;/button&gt;
    &lt;/div&gt;
  );
}</code></pre><blockquote>Otra cosa interesante a tener en cuenta si echa un vistazo a la documentación de React es que si no se devuelve nada de esta función, entonces no se volverá a renderizar en absoluto.</blockquote><p>Una vez que proporcionamos esta función interna a <code>setState</code> para obtener de manera confiable el estado anterior y devolver el nuevo estado de nuestra función, nuestro problema de estado obsoleto debido a nuestro closure desaparece.</p><p>Traducido del artículo de<strong><strong> <a href="https://www.freecodecamp.org/news/author/reed/">Reed Barger</a> - </strong><a href="https://www.freecodecamp.org/news/what-every-react-developer-should-know-about-state/">What Every React Developer Should Know About State</a></strong><br></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo obtener datos en React desde una API GraphQL ]]>
                </title>
                <description>
                    <![CDATA[ Repasemos las cinco mejores formas en que puede obtener datos con React desde una API GraphQL Si bien hay un par de bibliotecas populares que están diseñadas para interactuar con las API de GraphQL desde una aplicación React, hay muchas formas diferentes de obtener datos con GraphQL. He incluido ejemplos ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-obtener-datos-en-react-desde-una-api-graphql/</link>
                <guid isPermaLink="false">60c5ecf2e2d48208e1f4125c</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan C. Guaña ]]>
                </dc:creator>
                <pubDate>Tue, 13 Jul 2021 13:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/07/5-ways-to-fetch-data-in-react-with-graphql-2.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Repasemos las cinco mejores formas en que puede obtener datos con React desde una API GraphQL</p><p>Si bien hay un par de bibliotecas populares que están diseñadas para interactuar con las API de GraphQL desde una aplicación React, hay muchas formas diferentes de obtener datos con GraphQL.</p><p>He incluido ejemplos de código que le muestran cómo buscar o "consultar" datos en el código más corto posible y cómo empezar a trabajar con cada uno de estos diferentes métodos para conectar React con GraphQL.</p><h2 id="empezamos"><strong>Empezamos</strong></h2><p>En estos ejemplos, usaremos la API de SpaceX GraphQL para buscar y mostrar las últimas 10 misiones que SpaceX ha realizado.</p><p>Siéntete libre de usar el código a continuación si está intentando conectar tu aplicación React con una API GraphQL. En estos ejemplos, vamos a pasar de la biblioteca cliente GraphQL más avanzada para React al enfoque más simple para consultar un endpoint GraphQL.</p><h2 id="1-apollo-client"><strong><strong>1. Apollo Client</strong></strong></h2><p>La biblioteca GraphQL más popular y completa es Apollo Client.</p><p>No solo puedes usarlo para obtener datos remotos con GraphQL, lo que estamos haciendo aquí, sino que nos permite administrar datos localmente, tanto a través de una caché interna como de una API de administración de estado completa.</p><p>Para comenzar con Apollo Client, debe instalar tanto la dependencia principal de Apollo Client como GraphQL:</p><pre><code class="language-bash">npm install @apollo/client graphql</code></pre><p>La idea detrás de Apollo Client es que se utilizará en toda tu aplicación. Para hacer esto, usará un componente Apollo Provider especial para pasar un cliente de Apollo creado a todo su árbol de componentes.</p><p>Cuando creas tu cliente Apollo, debes especificar un valor <code>uri</code>, es decir, un endpoint GraphQL. Además, debe especificar un caché.</p><p>Apollo Client viene con su propia memoria caché, que se utiliza para almacenar en caché o almacenar y administrar localmente sus consultas y sus datos relacionados:</p><pre><code class="language-js">import React from "react";
import ReactDOM from "react-dom";
import { ApolloProvider, ApolloClient, InMemoryCache } from "@apollo/client";

import App from "./App";

const client = new ApolloClient({
  uri: "https://api.spacex.land/graphql/",
  cache: new InMemoryCache()
});

const rootElement = document.getElementById("root");
ReactDOM.render(
  &lt;ApolloProvider client={client}&gt;
    &lt;App /&gt;
  &lt;/ApolloProvider&gt;,
  rootElement
);</code></pre><p>Una vez que hayas configurado el Provider y el cliente dentro de su componente App, puedes usar todos los diferentes enlaces de React que Apollo Client te brinda para todas las diferentes operaciones de GraphQL. Estos incluyen consultas, mutaciones y suscripciones. Incluso puedes usar el Apollo Client creado directamente usando un hook personalizado llamado <code>useApolloClient</code>.</p><p>Ya que solo estás consultando datos aquí, usarás el hook <code>useQuery.</code></p><p>Incluirás una consulta GraphQL como primer argumento para escribir su consulta. Utilizarás la función <code>gql</code>, que hace una serie de cosas, como darle resaltado de sintaxis del editor y la funcionalidad de formateo automático si usa la herramienta Prettier para su proyecto.</p><p>Una vez que ejecutas esta consulta, recupera los valores <code>data</code>, <code>loading</code>, y <code>error</code>:</p><pre><code class="language-js">import React from "react";
import { useQuery, gql } from "@apollo/client";

const FILMS_QUERY = gql`
  {
    launchesPast(limit: 10) {
      id
      mission_name
    }
  }
`;

export default function App() {
  const { data, loading, error } = useQuery(FILMS_QUERY);

  if (loading) return "Loading...";
  if (error) return &lt;pre&gt;{error.message}&lt;/pre&gt;

  return (
    &lt;div&gt;
      &lt;h1&gt;SpaceX Launches&lt;/h1&gt;
      &lt;ul&gt;
        {data.launchesPast.map((launch) =&gt; (
          &lt;li key={launch.id}&gt;{launch.mission_name}&lt;/li&gt;
        ))}
      &lt;/ul&gt;
    &lt;/div&gt;
  );
}</code></pre><p>Antes de mostrar sus datos, sus misiones, debes manejar el estado de carga. Cuando se encuentra en un estado de carga, estás obteniendo la consulta desde un punto final remoto.</p><p>También debes manejar cualquier error que ocurra. Puedes simular un error si comete un error de sintaxis en su consulta, como consultar un campo que no existe. Para manejar ese error, puedes regresar y mostrar convenientemente un mensaje de <code>error.message</code>.</p><h2 id="2-urql"><strong><strong>2. Urql</strong></strong></h2><p>Otra biblioteca con todas las funciones que conecta las aplicaciones React con las API GraphQL es urql.</p><p>Intenta brindarle muchas de las características y la sintaxis que tiene Apollo a la vez que es un poco más pequeño y requiere menos código de configuración. Brinda capacidades de almacenamiento en caché si lo deseas, pero no incluye una biblioteca de administración de estado integrada como lo hace Apollo.</p><p>Para usar urql como tu biblioteca cliente GraphQL, deberás instalar los paquetes urql y GraphQL.</p><pre><code class="language-bash">npm install urql graphql</code></pre><p>Al igual que Apollo, querrás utilizar el componente dedicado Provider &nbsp;y crear un cliente con su endpoint GraphQL. Ten en cuenta que no es necesario que especifiques un caché de fábrica.</p><pre><code class="language-js">import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { createClient, Provider } from 'urql';

const client = createClient({
  url: 'https://api.spacex.land/graphql/',
});

const rootElement = document.getElementById("root");
ReactDOM.render(
  &lt;Provider value={client}&gt;
    &lt;App /&gt;
  &lt;/Provider&gt;,
  rootElement
);</code></pre><p>Muy similar a Apollo, urql te brinda hooks personalizados que manejan todas las operaciones estándar de GraphQL y, por lo tanto, tienen nombres similares.</p><p>Nuevamente, puedes usar el hook <code>useQuery</code> del paquete urql. Aunque en lugar de necesitar la función gql, puedes eliminarla y usar una plantilla literal para escribir su consulta.</p><p>Al llamar a <code>useQuery</code>, obtienes un arreglo que puedes desestructurar como una arreglo en lugar de como un objeto. El primer elemento de este arreglo es un objeto, llamado <code>result</code>, que te proporciona una serie de propiedades que puede desestructurar: <code>data</code>, <code>fetching</code>, y <code>error</code>.<br></p><pre><code class="language-js">import React from "react";
import { useQuery } from 'urql';

const FILMS_QUERY = `
  {
    launchesPast(limit: 10) {
      id
      mission_name
    }
  }
`;

export default function App() {
  const [result] = useQuery({
    query: FILMS_QUERY,
  });

  const { data, fetching, error } = result;

  if (fetching) return "Loading...";
  if (error) return &lt;pre&gt;{error.message}&lt;/pre&gt;

  return (
    &lt;div&gt;
      &lt;h1&gt;SpaceX Launches&lt;/h1&gt;
      &lt;ul&gt;
        {data.launchesPast.map((launch) =&gt; (
          &lt;li key={launch.id}&gt;{launch.mission_name}&lt;/li&gt;
        ))}
      &lt;/ul&gt;
    &lt;/div&gt;
  );
}</code></pre><p>De manera idéntica a la visualización de los datos que obtienes con Apollo, puedes manejar tanto su error como los estados de carga mientras obtienes sus datos remotos.</p><h2 id="3-react-query-graphql-request"><strong><strong>3. React Query + GraphQL Request</strong></strong></h2><p>Es importante tener en cuenta en este punto que no necesitas una biblioteca cliente GraphQL sofisticada y pesada como urql o Apollo para interactuar con tu API GraphQL, como veremos más adelante.</p><p>Las bibliotecas como Apollo y urql se crearon no solo para ayudarte a realizar todas las operaciones estándar de GraphQL, sino para administrar mejor el estado del servidor en tu cliente React a través de una serie de herramientas adicionales. Todo esto junto con el hecho de que vienen con hooks personalizados que facilitan la administración de tareas repetitivas como manejar la carga, el error y otros estados relacionados.</p><p>Con eso en mente, echemos un vistazo a cómo puedes usar una biblioteca GraphQL muy reducida para la búsqueda de datos y combinarla con una mejor manera de administrar y almacenar en caché el estado del servidor que está incorporando a tu aplicación. Puedes obtener datos de forma muy sencilla con la ayuda del paquete <code>graphql-request</code>.</p><p>GraphQL Request es una biblioteca que no requiere que configure un cliente o un componente Provider. Esencialmente es una función que solo acepta un endpoint y una consulta. Muy similar a un cliente HTTP, solo tienes que pasar esos dos valores y recuperar tus datos.</p><p>Ahora, si quieres administrar ese estado en tu aplicación, puedes usar una gran biblioteca que se usa normalmente para interactuar con las API Rest, pero es igualmente útil para las API GraphQL, y esa es React Query. Brinda algunos React Hooks con nombres muy similares, <code>useQuery</code> y <code>useMutation</code>, que realizan tareas idénticas a las que realizan los hooks de Apollo y urql.</p><p>React Query también te brinda un montón de herramientas para administrar el estado, junto con un componente Dev Tools integrado que te permite ver lo que se almacena en la memoria caché incorporada de React Query.</p><blockquote>Al emparejar tu cliente GraphQL muy básico, la solicitud GraphQL, con React Query, obtiene todo el poder de una biblioteca como urql o Apollo.<br></blockquote><p>Para comenzar con este emparejamiento, solo necesita instalar React Query y GraphQL Request:</p><pre><code class="language-bash">npm install react-query graphql-request</code></pre><p>Utiliza el componente Provider de React Query y crea un cliente de consulta donde puede establecer algunas configuraciones predeterminadas de obtención de datos si lo deseas. Luego, dentro de tu componente App, o cualquier componente secundario de la aplicación, puedes usar el gancho useQuery.</p><pre><code class="language-js">import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import { QueryClient, QueryClientProvider } from "react-query";

const client = new QueryClient();

const rootElement = document.getElementById("root");
ReactDOM.render(
  &lt;QueryClientProvider client={client}&gt;
    &lt;App /&gt;
  &lt;/QueryClientProvider&gt;,
  rootElement
);</code></pre><p>Para almacenar el resultado de tu operación en el caché de React Query, solo necesitas darle un valor clave como primer argumento para que sirva como identificador. Esto le permite hacer referencia y extraer datos de la caché con mucha facilidad, así como recuperar o invalidar una consulta determinada para obtener datos actualizados.</p><p>Ya que está obteniendo datos de lanzamiento, llamemos a esta consulta "launches".</p><p>Una vez más, este gancho devolverá el resultado de realizar esa solicitud. Para que el segundo argumento <code>useQuery</code>, debes especificar cómo obtener esos datos y React Query se encargará de resolver la promesa que devuelve la solicitud GraphQL.</p><pre><code class="language-js">import React from "react";
import { request, gql } from "graphql-request";
import { useQuery } from "react-query";

const endpoint = "https://api.spacex.land/graphql/";
const FILMS_QUERY = gql`
  {
    launchesPast(limit: 10) {
      id
      mission_name
    }
  }
`;

export default function App() {
  const { data, isLoading, error } = useQuery("launches", () =&gt; {
    return request(endpoint, FILMS_QUERY);
  });

  if (isLoading) return "Loading...";
  if (error) return &lt;pre&gt;{error.message}&lt;/pre&gt;;

  return (
    &lt;div&gt;
      &lt;h1&gt;SpaceX Launches&lt;/h1&gt;
      &lt;ul&gt;
        {data.launchesPast.map((launch) =&gt; (
          &lt;li key={launch.id}&gt;{launch.mission_name}&lt;/li&gt;
        ))}
      &lt;/ul&gt;
    &lt;/div&gt;
  );
}</code></pre><p>Al igual que en Apollo, obtienes un objeto que puedes desestructurar para obtener los valores de los datos, así como si estás o no en el estado de carga y el estado de error.</p><h2 id="4-react-query-axios"><strong><strong>4. React Query + Axios</strong></strong></h2><p>Puedes usar bibliotecas de cliente HTTP aún más simples que no tienen relación con GraphQL para obtener sus datos.</p><p>En este caso, puedes utilizar la popular biblioteca axios. Una vez más, puedes emparejarlo con React Query para obtener todos los ganchos especiales y la administración del estado.</p><pre><code class="language-bash">npm install react-query axios</code></pre><p>El uso de un cliente HTTP como axios para realizar una consulta desde una API GraphQL requiere realizar una solicitud POST al endpoint de la API. Para los datos que envíes en la solicitud, tú proporcionarás un objeto con una propiedad llamada <code>query</code>, que se establecerá en la consulta de su película.</p><p>Con axios, necesitarás incluir un poco más de información sobre cómo resolver esta promesa y recuperar sus datos. Necesitas decirle a React Query dónde están los datos para que puedan colocarse en la propiedad <code>data</code> que devuelve <code>useQuery</code>.</p><p>En particular, recuperas los datos en la propiedad datos de <code>response.data</code>:</p><pre><code class="language-js">import React from "react";
import axios from "axios";
import { useQuery } from "react-query";

const endpoint = "https://api.spacex.land/graphql/";
const FILMS_QUERY = `
  {
    launchesPast(limit: 10) {
      id
      mission_name
    }
  }
`;

export default function App() {
  const { data, isLoading, error } = useQuery("launches", () =&gt; {
    return axios({
      url: endpoint,
      method: "POST",
      data: {
        query: FILMS_QUERY
      }
    }).then(response =&gt; response.data.data);
  });

  if (isLoading) return "Loading...";
  if (error) return &lt;pre&gt;{error.message}&lt;/pre&gt;;

  return (
    &lt;div&gt;
      &lt;h1&gt;SpaceX Launches&lt;/h1&gt;
      &lt;ul&gt;
        {data.launchesPast.map((launch) =&gt; (
          &lt;li key={launch.id}&gt;{launch.mission_name}&lt;/li&gt;
        ))}
      &lt;/ul&gt;
    &lt;/div&gt;
  );
}</code></pre><h2 id="5-react-query-fetch-api"><strong><strong>5. React Query + Fetch API</strong></strong></h2><p>La forma más fácil de todos estos diferentes enfoques para obtener datos es simplemente usar la consulta React más la fetch API.</p><p>Dado que la fetch API está incluida en todos los navegadores modernos, no necesitas instalar una biblioteca de terceros, solo necesita instalar <code>react-query</code> dentro de su aplicación.</p><pre><code class="language-bash">npm install react-query</code></pre><p>Una vez que tengas el cliente React Query proporcionado a toda la aplicación, puedes simplemente intercambiar su código axios con fetch.</p><p>Lo que es un poco diferente es que debe especificar un encabezado que incluya el tipo de contenido de los datos que deseas recuperar de tu solicitud. En este caso, son datos JSON.</p><p>También necesitas utilizar el método stringify en el objeto que estás enviando como su payload con una propiedad de consulta que está configurada para su consulta de películas:<br></p><pre><code class="language-js">import React from "react";
import axios from "axios";
import { useQuery } from "react-query";

const endpoint = "https://api.spacex.land/graphql/";
const FILMS_QUERY = `
  {
    launchesPast(limit: 10) {
      id
      mission_name
    }
  }
`;

export default function App() {
  const { data, isLoading, error } = useQuery("launches", () =&gt; {
    return fetch(endpoint, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ query: FILMS_QUERY })
    })
      .then((response) =&gt; {
        if (response.status &gt;= 400) {
          throw new Error("Error fetching data");
        } else {
          return response.json();
        }
      })
      .then((data) =&gt; data.data);
  });

  if (isLoading) return "Loading...";
  if (error) return &lt;pre&gt;{error.message}&lt;/pre&gt;;

  return (
    &lt;div&gt;
      &lt;h1&gt;SpaceX Launches&lt;/h1&gt;
      &lt;ul&gt;
        {data.launchesPast.map((launch) =&gt; (
          &lt;li key={launch.id}&gt;{launch.mission_name}&lt;/li&gt;
        ))}
      &lt;/ul&gt;
    &lt;/div&gt;
  );
}</code></pre><p>Una ventaja de usar axios sobre fetch es que maneja automáticamente los errores por ti. Con fetch, como puedes ver en el código anterior, se debe verificar un cierto código de estado, en particular, un código de estado superior a 400.</p><p>Esto significa que su solicitud se resuelve en un error. Si ese es el caso, debe lanzar manualmente un error, que será detectado por su hook <code>useQuery</code>. De lo contrario, si se trata de una respuesta de rango de 200 o 300, significa que la solicitud se realizó correctamente, simplemente devuelve los datos JSON y muéstralos.</p><h2 id="conclusi-n"><strong>Conclusión</strong></h2><p>Este artículo se dedicó a mostrarte una serie de enfoques diferentes para obtener datos de manera efectiva de una API GraphQL con React.</p><p>A partir de estas opciones, es de esperar que puedas evaluar cuál es la más adecuada para ti y tus aplicaciones. Y ahora tienes un código útil que te permitirá comenzar a usar estas herramientas y bibliotecas mucho más rápido.</p><p>Traducido del artículo de<strong> <a href="https://www.freecodecamp.org/news/author/reed/">Reed Barger</a> - <strong><a href="https://www.freecodecamp.org/news/5-ways-to-fetch-data-react-graphql/">How to Fetch Data in React from a GraphQL API</a></strong></strong></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo construir una aplicación en React con funcionalidad de cargar más usando React Hooks ]]>
                </title>
                <description>
                    <![CDATA[ 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 ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-construir-una-aplicacion-en-react-con-funcionalidad/</link>
                <guid isPermaLink="false">60a913e005c64a09104b5fc0</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan C. Guaña ]]>
                </dc:creator>
                <pubDate>Thu, 08 Jul 2021 05:24:40 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/07/random_user.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>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.</p><p>Al crear esta aplicación, aprenderás:</p><ul><li>Cómo hacer llamadas a una API</li><li>Cómo implementar funcionalidad de cargar más</li><li>Cómo depurar problemas de la aplicación</li><li>Cómo usar async/await</li><li>Cómo actualizar el componente cuando algo cambia</li><li>Cómo solucionar el problema del bucle infinito en el hook useEffect</li><li>Cómo refactorizar componentes basados ​​en clases en componentes funcionales con Hooks</li></ul><p>y mucho más.</p><p>Entonces empecemos.</p><h2 id="configuraci-n-inicial-del-proyecto"><strong>Configuración inicial del proyecto</strong></h2><p>Crea un nuevo proyecto usando <code>create-react-app</code>:</p><pre><code>npx create-react-app class-to-hooks-refactoring</code></pre><p>Una vez tu proyecto este creado, elimina todos los archivos de la carpeta <code>src</code> y crea el archivo <code>index.js</code> y el archivo <code>styles.css</code> dentro de la carpeta <code>src</code>. También, crea una carpeta <code>components</code> dentro de la carpeta <code>src</code>.</p><p>Instala la librería <code>axios</code> ejecutando el siguiente comando desde la carpeta de tu proyecto:</p><pre><code>yarn add axios@0.21.1
</code></pre><p>Abre el archivo <code>styles.css</code> y agrega el contenido desde este <a href="https://github.com/myogeshchavan97/class-to-hooks-refactoring/blob/master/src/styles.css">repositorio de GitHub</a>.</p><h2 id="c-mo-crear-las-p-ginas-iniciales"><strong>Cómo crear las páginas iniciales</strong></h2><p>Crea un nuevo archivo llamado <code>Header.js</code> dentro de la carpeta <code>components</code> con el siguiente contenido:</p><pre><code class="language-jsx">import React from "react";

const Header = () =&gt; {
  return &lt;h1 className="header"&gt;Random Users&lt;/h1&gt;;
};

export default Header;
</code></pre><p>Crea un nuevo archivo llamado <code>App.js</code> dentro de la carpeta <code>src</code> con el siguiente contenido:</p><pre><code class="language-jsx">import React from 'react';
import Header from './components/Header';

export default class App extends React.Component {
  render() {
    return (
      &lt;div className="main-section"&gt;
        &lt;Header /&gt;
        &lt;h2&gt;App Component&lt;/h2&gt;
      &lt;/div&gt;
    );
  }
}
</code></pre><p>Ahora, abre el archivo <code>index.js</code> y agrega el siguiente contenido en él:</p><pre><code class="language-js">import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './styles.css';

ReactDOM.render(&lt;App /&gt;, document.getElementById('root'));
</code></pre><p>Ahora, inicia la aplicación ejecutando el comando <code>yarn start</code> desde la terminal.</p><p>Podrás ver la siguiente pantalla sí accedes a la aplicación en <a href="http://localhost:3000/">http://localhost:3000/</a>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/index_page.png" class="kg-image" alt="index_page" width="600" height="400" loading="lazy"></figure><h2 id="c-mo-hacer-llamadas-a-una-api"><strong>Cómo hacer llamadas a una API</strong></h2><p>Usaremos la API de <a href="https://randomuser.me/">Random Users</a> para obtener una lista de usuarios aleatorios.</p><p>Así que abre tu archivo <code>App.js</code> y agrega el método <code>componentDidMount</code> dentro del componente:</p><pre><code class="language-js">componentDidMount() {
    axios
      .get('https://randomuser.me/api/?page=0&amp;results=10')
      .then((response) =&gt; {
        console.log(response.data);
      })
      .catch((error) =&gt; console.log('error', error));
  }
</code></pre><p>También, importa <code>axios</code> en la parte superior del archivo:</p><pre><code class="language-js">import axios from 'axios';
</code></pre><p>Todo su archivo <code>App.js</code> se verá así ahora:</p><pre><code class="language-js">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&amp;results=10')
      .then((response) =&gt; {
        console.log(response.data);
      })
      .catch((error) =&gt; console.log('error', error));
  }

  render() {
    return (
      &lt;div className="main-section"&gt;
        &lt;Header /&gt;
        &lt;h2&gt;App Component&lt;/h2&gt;
      &lt;/div&gt;
    );
  }
}
</code></pre><p>Aquí, estamos haciendo una llamada al API para obtener inicialmente una lista de 10 registros en la URL <code>https://randomuser.me/api/?page=0&amp;results=10</code>.</p><p>Ahora, si verificas la aplicación, verás la respuesta del API en la consola.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/result-1.png" class="kg-image" alt="result-1" width="600" height="400" loading="lazy"></figure><p>Ahora, declaremos un estado para almacenar el resultado y los indicadores relacionados con la carga y los mensajes de error.</p><p>Reemplaza el contenido de <code>App.js</code> con el siguiente código:</p><pre><code class="language-js">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&amp;results=10')
      .then((response) =&gt; {
         this.setState({ users: response.data.results, errorMsg: '' });
      })
      .catch((error) =&gt;
        this.setState({
          errorMsg: 'Error while loading data. Try again later.'
        })
      )
      .finally(() =&gt; {
        this.setState({ isLoading: false });
      });
  }

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

    return (
      &lt;div className="main-section"&gt;
        &lt;Header /&gt;
        {isLoading &amp;&amp; &lt;p className="loading"&gt;Loading...&lt;/p&gt;}
        {errorMsg &amp;&amp; &lt;p className="errorMsg"&gt;{errorMsg}&lt;/p&gt;}
      &lt;/div&gt;
    );
  }
}
</code></pre><p>Aquí, hemos declarado un estado directamente dentro de la clase usando la <a href="https://javascript.plainenglish.io/how-to-write-clean-and-easy-to-understand-react-code-using-class-properties-syntax-5b375b0618d3?source=friends_link&amp;sk=c170992cab9025fddb7b34b8894ea993">sintaxis de propiedades de la clase</a>, que es una forma común de escribir el estado en componentes basados ​​en clases.</p><pre><code class="language-js">state = {
  users: [],
  isLoading: false,
  errorMsg: ''
};
</code></pre><p>Luego, dentro del método <code>componentDidMount</code> primero establecemos el estado <code>isLoading</code> en <code>true</code> antes de realizar la llamada a la API.</p><pre><code class="language-js">this.setState({ isLoading: true });
</code></pre><p>Una vez que obtenemos la respuesta del API, almacenamos el resultado en la matriz de <code>users</code> que se declara en el estado. También estamos configurando el estado de <code>errorMsg</code> en vacío, de modo que si hay algún error anterior, se borrará.</p><pre><code class="language-js">this.setState({ users: response.data.results, errorMsg: '' });
</code></pre><p>Y en el bloque <code>.catch</code>, estamos configurando el <code>errorMsg</code> en caso de que haya algún error al realizar una llamada a la API.</p><p>Luego, usamos el bloque <code>.finally</code> para establecer el estado <code>isLoading</code> en <code>false</code>.</p><pre><code class="language-js">.finally(() =&gt; {
  this.setState({ isLoading: false });
});
</code></pre><p>Usar <code>finally</code> nos ayuda a evitar la duplicación de código aquí porque no necesitamos establecer <code>isLoading</code> a <code>false</code> en <code>.then</code> y en el bloque <code>.catch</code> nuevamente. Esto se debe a que el bloque <code>finally</code> se ejecutará siempre, tenga éxito o no.</p><p>Y en el método <code>render</code>, mostramos el mensaje de error o el mensaje de carga junto con la matriz de <code>users</code> desde el estado en la consola.</p><p>Ahora, si verificas la aplicación, verás la información de <code>users</code> en la consola sobre el éxito o un mensaje de error en la UI por falla del API.</p><h2 id="c-mo-mostrar-la-informaci-n-de-los-usuarios"><strong>Cómo mostrar la información de los usuarios</strong></h2><p>Ahora, mostremos la información <code>users</code> en la pantalla.</p><p>Crea un nuevo archivo <code>User.js</code> dentro de la carpeta <code>components</code> con el siguiente contenido:</p><pre><code class="language-js">import React from "react";

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

export default User;
</code></pre><p>Ahora, crea un nuevo archivo <code>UsersList.js</code> dentro de la carpeta <code>components</code> con el siguiente contenido:</p><pre><code class="language-js">import React from 'react';
import User from './User';

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

export default UsersList;
</code></pre><p>Ahora, abre el archivo <code>App.js</code> y reemplaza el método <code>render</code> con el siguiente código:</p><pre><code class="language-js">render() {
  const { users, isLoading, errorMsg } = this.state;

  return (
    &lt;div className="main-section"&gt;
      &lt;Header /&gt;
      {isLoading &amp;&amp; &lt;p className="loading"&gt;Loading...&lt;/p&gt;}
      {errorMsg &amp;&amp; &lt;p className="errorMsg"&gt;{errorMsg}&lt;/p&gt;}
      &lt;UsersList users={users} /&gt;
    &lt;/div&gt;
  );
}
</code></pre><p>Aquí, estamos pasando el arreglo de <code>users</code> como propiedades al componente <code>UsersList</code>. Dentro del componente <code>UsersList</code>, estamos recorriendo el arreglo y enviando la información del usuario al componente <code>User</code> mediante la distribución de todas las propiedades del <code>user</code> individual como <code>{...props}</code>. Esto finalmente muestra los datos en la pantalla.</p><p>Además, importa el componente <code>UsersList</code> en la parte superior del archivo:</p><pre><code class="language-js">import UsersList from './components/UsersList';
</code></pre><p>Si revisas la aplicación ahora, verás la siguiente pantalla:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/04/random_users.gif" class="kg-image" alt="random_users" width="600" height="400" loading="lazy"></figure><p>Como puedes ver, en cada actualización de página, se muestra un nuevo conjunto de usuarios aleatorios en la pantalla.</p><h2 id="c-mo-implementar-funcionalidad-de-cargar-m-s"><strong>Cómo implementar funcionalidad de cargar más</strong></h2><p>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.</p><p>Cambia el método <code>render</code> del archivo <code>App.js</code> al siguiente código:</p><pre><code class="language-js">render() {
  const { users, isLoading, errorMsg } = this.state;

  return (
    &lt;div className="main-section"&gt;
      &lt;Header /&gt;
      &lt;UsersList users={users} /&gt;
      {errorMsg &amp;&amp; &lt;p className="errorMsg"&gt;{errorMsg}&lt;/p&gt;}
      &lt;div className="load-more"&gt;
        &lt;button onClick={this.loadMore} className="btn-grad"&gt;
          {isLoading ? 'Loading...' : 'Load More'}
        &lt;/button&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  );
}
</code></pre><p>Aquí, hemos agregado la condición <code>isLoading</code> dentro del botón para mostrar el texto <code>Loading...</code> o <code>Load More</code> en el botón.</p><p>Agrega la nueva propiedad <code>page</code> al estado e inicialízala en <code>0</code>.</p><pre><code class="language-js">state = {
  users: [],
  page: 0,
  isLoading: false,
  errorMsg: ''
};
</code></pre><p>Y agrega la función <code>loadMore</code> antes del método <code>render</code> para incrementar el valor del estado de <code>page</code> en 1 en cada clic de botón.</p><pre><code class="language-js">loadMore = () =&gt; {
  this.setState((prevState) =&gt; ({
    page: prevState.page + 1
  }));
};
</code></pre><p>Aquí, estamos usando el estado anterior para calcular el siguiente valor de estado <code>page</code>, por lo que el código anterior es el mismo que el código siguiente:</p><pre><code class="language-js">loadMore = () =&gt; {
  this.setState((prevState) =&gt; {
    return {
      page: prevState.page + 1
    };
  });
};
</code></pre><p>Solo estamos usando la sintaxis abreviada de ES6 para devolver un objeto de la función.</p><p>Ahora, dentro del método <code>componentDidMount</code>, cambie la URL del API &nbsp;con el código:</p><pre><code class="language-js">'https://randomuser.me/api/?page=0&amp;results=10'
</code></pre><p>a este código:</p><pre><code class="language-js">`https://randomuser.me/api/?page=${page}&amp;results=10`
</code></pre><p>Aquí, estamos usando la sintaxis de plantilla literal ES6 para usar el valor dinámico del estado de <code>page</code> para cargar el siguiente conjunto de usuarios en cada clic de botón.</p><p>Desestructuramos <code>page</code> desde el estado dentro del método <code>componentDidMount</code> de esta manera:</p><pre><code class="language-js">componentDidMount() {
  const { page } = this.state;
  ....
}
</code></pre><p>Ahora, revisemos la funcionalidad de la aplicación.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/load_more_state_changing.gif" class="kg-image" alt="load_more_state_changing" width="600" height="400" loading="lazy"></figure><p>Como puedes ver, cuando hacemos clic en el botón <code>Load More</code>, el estado de <code>page</code> está cambiando en las herramientas de desarrollo de react, pero no aparece la nueva lista de usuarios en la pantalla.</p><p>Esto se debe a que, aunque estamos cambiando el estado de <code>page</code>, no volvemos a realizar una llamada al API para obtener el siguiente grupo de usuarios con el valor de <code>page</code> modificado. Así que arreglemos esto.</p><p>Crea una nueva función <code>loadUsers</code> encima de la función <code>loadMore</code> y mueve todo el código de <code>componentDidMount</code> al interior de la función <code>loadUsers</code>. Luego llama a la función <code>loadUsers</code> desde el método <code>componentDidMount</code>.</p><p>También, agrega el método <code>componentDidUpdate</code> dentro del componente de la aplicación como este:</p><pre><code class="language-js">componentDidUpdate(prevProps, prevState) {
  if (prevState.page !== this.state.page) {
    this.loadUsers();
  }
}
</code></pre><p>Como estamos actualizando el valor del estado de <code>page</code> en la función <code>loadMore</code> una vez que se actualiza el estado, se llamará al método <code>componentDidUpdate</code>. Entonces, estamos verificando si el valor del estado anterior de <code>page</code> no es igual al valor del estado actual. Luego volvemos a hacer la llamada al API llamando a la función <code>loadUsers</code>.</p><blockquote>Revisa el <a href="https://www.freecodecamp.org/news/what-is-state-in-react-explained-with-examples/">siguiente artículo</a> para aprender más sobre por qué y cuándo necesitamos usar el método <code>componentDidUpdate</code> .</blockquote><p>Tu archivo completo <code>App.js</code> se verá así ahora:</p><pre><code class="language-js">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 = () =&gt; {
    const { page } = this.state;

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

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

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

    return (
      &lt;div className="main-section"&gt;
        &lt;Header /&gt;
        &lt;UsersList users={users} /&gt;
        {errorMsg &amp;&amp; &lt;p className="errorMsg"&gt;{errorMsg}&lt;/p&gt;}
        &lt;div className="load-more"&gt;
          &lt;button onClick={this.loadMore} className="btn-grad"&gt;
            {isLoading ? 'Loading...' : 'Load More'}
          &lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    );
  }
}
</code></pre><p>Ahora, si vuelves a comprobar la aplicación ejecutando el comando <code>yarn start</code>, verás la siguiente pantalla:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/04/new_users_loaded.gif" class="kg-image" alt="new_users_loaded" width="600" height="400" loading="lazy"></figure><p>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.</p><p>Así que hagamos cambios para agregar nuevos usuarios a la lista de usuarios que ya se muestra.</p><p>Para esto, necesitamos cambiar la forma en que configuramos el estado de <code>users</code>.</p><p>Nuestra llamada <code>setState</code> actual dentro de la función <code>loadUsers</code> se ve así:</p><pre><code class="language-js">this.setState({ users: response.data.results, errorMsg: '' });
</code></pre><p>Aquí, siempre reemplazamos el arreglo de <code>users</code> con el nuevo conjunto de usuarios. Así que cambie la llamada <code>setState</code> anterior al siguiente código:</p><pre><code class="language-js">this.setState((prevState) =&gt; ({
  users: [...prevState.users, ...response.data.results],
  errorMsg: ''
}));
</code></pre><p>Aquí, estamos usando la sintaxis del actualizador de <code>setState</code>. Estamos creando un nuevo arreglo distribuyendo los <code>users</code> ya agregados usando <code>...prevState.users</code>, y luego agregamos un nuevo conjunto de <code>users</code> usando <code>..response.data.results</code>.</p><p>De esta manera, no perderemos los datos de los <code>users</code> cargados anteriormente y también podremos agregar un nuevo conjunto de <code>users</code>.</p><p>Ahora, si vuelves a comprobar la aplicación, verás el comportamiento correcto de la carga de datos.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/correct_loading.gif" class="kg-image" alt="correct_loading" width="600" height="400" loading="lazy"></figure><h2 id="c-mo-mejorar-el-c-digo-usando-async-await"><strong>Cómo mejorar el código usando Async/await</strong></h2><p>Si revisas la función <code>loadUsers</code>, verás que el código parece complejo y difícil de leer.</p><pre><code class="language-js">loadUsers = () =&gt; {
  const { page } = this.state;

  this.setState({ isLoading: true });
  axios
    .get(`https://randomuser.me/api/?page=${page}&amp;results=10`)
    .then((response) =&gt; {
      this.setState((prevState) =&gt; ({
        users: [...prevState.users, ...response.data.results],
        errorMsg: ''
      }));
    })
    .catch((error) =&gt;
      this.setState({
        errorMsg: 'Error while loading data. Try again later.'
      })
    )
    .finally(() =&gt; {
      this.setState({ isLoading: false });
    });
};
</code></pre><p>Podemos arreglar esto usando la sintaxis async/await.</p><p>Primero, necesitamos marcar la función <code>loadUsers</code> como asíncrona:</p><pre><code class="language-js">loadUsers = async () =&gt; {
</code></pre><p>Porque podemos usar la palabra clave <code>await</code> solo dentro de la función que se declara como <code>async</code>.</p><p>Ahora, reemplaza la función <code>loadUsers</code> con el siguiente código:</p><pre><code class="language-js">loadUsers = async () =&gt; {
  try {
    const { page } = this.state;

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

    this.setState((prevState) =&gt; ({
      users: [...prevState.users, ...response.data.results],
      errorMsg: ''
    }));
  } catch (error) {
    this.setState({
      errorMsg: 'Error while loading data. Try again later.'
    });
  } finally {
    this.setState({ isLoading: false });
  }
};
</code></pre><p>Aquí, hemos usado la palabra clave <code>await</code> antes de la llamada <a href="https://www.freecodecamp.org/espanol/news/p/4a3745e2-1870-4e93-bdb2-641fc8c2d7ee/axios.get"></a><a href="https://www.freecodecamp.org/espanol/news/p/4a3745e2-1870-4e93-bdb2-641fc8c2d7ee/axios.get"><code>axios.get</code></a>, por lo que la siguiente línea de código, que es la llamada <code>setState</code>, no se ejecutará hasta que obtengamos la respuesta del API.</p><p>Si hay algún error al obtener la respuesta del API, se ejecutará el bloque <code>catch</code>. El bloque <code>finally</code> establecerá el estado <code>isLoading</code> en <code>false</code>.</p><p>Tu archivo <code>App.js</code> modificado se verá así ahora:</p><pre><code class="language-js">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 () =&gt; {
    try {
      const { page } = this.state;

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

      this.setState((prevState) =&gt; ({
        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 = () =&gt; {
    this.setState((prevState) =&gt; ({
      page: prevState.page + 1
    }));
  };

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

    return (
      &lt;div className="main-section"&gt;
        &lt;Header /&gt;
        &lt;UsersList users={users} /&gt;
        {errorMsg &amp;&amp; &lt;p className="errorMsg"&gt;{errorMsg}&lt;/p&gt;}
        &lt;div className="load-more"&gt;
          &lt;button onClick={this.loadMore} className="btn-grad"&gt;
            {isLoading ? 'Loading...' : 'Load More'}
          &lt;/button&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    );
  }
}
</code></pre><p>Ahora, el código de la función <code>loadUsers</code> 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.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/correct_loading-1.gif" class="kg-image" alt="correct_loading-1" width="600" height="400" loading="lazy"></figure><h2 id="c-mo-refactorizar-el-c-digo-de-componente-de-clase-en-c-digo-de-componente-funcional"><strong>Cómo refactorizar el código de componente de clase en código de componente funcional</strong></h2><p>Hemos terminado de desarrollar la funcionalidad completa de la aplicación. Así que refactoricemos el código para usar componentes funcionales con React Hooks.</p><blockquote>Si eres nuevo en React Hooks, revisa el <a href="https://levelup.gitconnected.com/an-introduction-to-react-hooks-50281fd961fe?source=friends_link&amp;sk=89baff89ec8bc637e7c13b7554904e54">siguiente articulo</a> para una introducción a los Hooks.</blockquote><p>Crea un nuevo archivo llamado <code>AppFunctional.js</code> dentro de la carpeta <code>src</code> con el siguiente contenido:</p><pre><code class="language-js">import React from 'react';

const AppFunctional = () =&gt; {
  return (
    &lt;div&gt;
      &lt;h2&gt;Functional Component&lt;/h2&gt;
    &lt;/div&gt;
  );
};

export default AppFunctional;
</code></pre><p>Hemos creado un nuevo archivo para el componente funcional para que pueda comparar el código y guardarlo para su referencia.</p><p>Ahora, abre el archivo <code>index.js</code> y reemplaza el contenido del archivo con el siguiente código:</p><pre><code class="language-js">import React from 'react';
import ReactDOM from 'react-dom';
import AppFunctional from './AppFunctional';
import './styles.css';

ReactDOM.render(&lt;AppFunctional /&gt;, document.getElementById('root'));
</code></pre><p>Aquí, hemos utilizado el componente <code>AppFunctional</code> dentro del método <code>render</code> y también hemos agregado la importación para él mismo en la parte superior del archivo.</p><p>Ahora, si vuelves a arrancar tu aplicación usando el comando <code>yarn start</code>, verás la siguiente pantalla:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/functional_component.png" class="kg-image" alt="functional_component" width="600" height="400" loading="lazy"></figure><p>Entonces, estamos mostrando correctamente el código del componente <code>AppFunctional</code> en la pantalla.</p><p>Ahora, reemplace el contenido del componente <code>AppFunctional</code> con el siguiente código:</p><pre><code class="language-js">import React, { useState, useEffect } from 'react';
import axios from 'axios';
import Header from './components/Header';
import UsersList from './components/UsersList';

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

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

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

    loadUsers();
  }, []);

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

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

export default AppFunctional;
</code></pre><p>Aquí, inicialmente declaramos los estados requeridos usando el hook <code>useState</code>:</p><pre><code class="language-js">const [users, setUsers] = useState([]);
const [page, setPage] = useState(0);
const [isLoading, setIsLoading] = useState(false);
const [errorMsg, setErrorMsg] = useState('');
</code></pre><p>Luego agregamos un hook <code>useEffect</code> y le pasamos un arreglo vacío <code>[]</code> como segundo argumento. Esto significa que el código dentro del hook <code>useEffect</code> se ejecutará solo una vez cuando se monte el componente.</p><pre><code class="language-js">useEffect(() =&gt; {
 // your code
}, []);
</code></pre><p>Hemos trasladado toda la función <code>loadUsers</code> dentro del hook <code>useEffect</code> y luego la llamamos dentro del gancho de esta manera:</p><pre><code class="language-js">useEffect(() =&gt; {
  const loadUsers = async () =&gt; {
    // your code
  };

  loadUsers();
}, []);
</code></pre><p>También hemos eliminado todas las referencias a <code>this.state</code> ya que los componentes funcionales no necesitan el contexto <code>this</code>.</p><p>Antes de realizar la llamada al API, establecemos el estado <code>isLoading</code> en <code>true</code> usando <code>setIsLoading(true);</code>.</p><p>Como ya tenemos acceso al arreglo de <code>users</code> dentro del componente, estamos configurando directamente como una nuevo arreglo para la función <code>setUsers</code> de esta manera:</p><pre><code class="language-js">setUsers([...users, ...response.data.results]);
</code></pre><blockquote>Si quieres saber porqué no podemos usar la palabra clave <code>async</code> directamente en la función hook <code>useEffect</code>, revisa el <a href="https://javascript.plainenglish.io/handling-api-calls-using-async-await-in-useeffect-hook-990fb4ae423?source=friends_link&amp;sk=dd686f066a434c41a76c352e3ec69767">siguiente articulo</a>.</blockquote><p>Luego, hemos cambiado la función <code>loadMore</code> de éste código:</p><pre><code class="language-js">loadMore = () =&gt; {
  this.setState((prevState) =&gt; ({
    page: prevState.page + 1
  }));
};
</code></pre><p> a éste código:</p><pre><code class="language-js">const loadMore = () =&gt; {
  setPage((page) =&gt; page + 1);
};
</code></pre><blockquote>Tenga en cuenta que para declarar una función basada en componentes funcionales, debe agregar <code>const</code> o <code>let</code> antes de la declaración. Como la función no va a cambiar, se recomienda usar <code>const</code> por ejemplo <code>const loadMore = () =&gt; {}</code>.</blockquote><p>Luego, copiamos el contenido del método <code>render</code> tal como está dentro del componente <code>AppFunctional</code> para devolver el JSX. También hemos cambiado <code>onClick = {this.loadMore}</code> a <code>onClick = {loadMore}</code>.</p><pre><code class="language-jsx">return (
  &lt;div className="main-section"&gt;
    &lt;Header /&gt;
    &lt;UsersList users={users} /&gt;
    {errorMsg &amp;&amp; &lt;p className="errorMsg"&gt;{errorMsg}&lt;/p&gt;}
    &lt;div className="load-more"&gt;
      &lt;button onClick={loadMore} className="btn-grad"&gt;
        {isLoading ? 'Loading...' : 'Load More'}
      &lt;/button&gt;
    &lt;/div&gt;
  &lt;/div&gt;
);
</code></pre><p>Ahora, si revisas la aplicación, verás la siguiente pantalla:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/functional_load_more_not_working.gif" class="kg-image" alt="functional_load_more_not_working" width="600" height="400" loading="lazy"></figure><p>Como puedes ver, los usuarios se están cargando correctamente, pero la funcionalidad de carga más no funciona.</p><p>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 <code>[]</code> como segundo argumento para el hook <code>useEffect</code>.</p><p>Para hacer la llamada al API nuevamente cuando cambia el estado de <code>page</code>, necesitamos agregar la <code>page</code> como una dependencia para el hook <code>useEffect</code> como este:</p><pre><code class="language-js">useEffect(() =&gt; {
  // execute the code to load users
}, [page]);
</code></pre><p>El <code>useEffect</code> anterior es lo mismo que escribir el siguiente código:</p><pre><code class="language-js">componentDidUpdate(prevProps, prevState) {
  if (prevState.page !== this.state.page) {
    // execute the code to load users
  }
}
</code></pre><p> <code>useEffect</code> hace que sea realmente fácil escribir menos código que sea fácil de entender.</p><p>Entonces, ahora con este cambio, el código dentro del hook <code>useEffect</code> se ejecutará cuando el componente se monte y cuando se cambie el estado <code>page</code>.</p><p>Ahora, si revisas la aplicación, verás que la funcionalidad de carga más está funcionando nuevamente como se esperaba.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/correct_loading-2.gif" class="kg-image" alt="correct_loading-2" width="600" height="400" loading="lazy"></figure><p>Pero si verificas la terminal/símbolo del sistema, es posible que observes una advertencia como se muestra a continuación (si tienes <code>ESLint</code> instalado en su máquina):</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/eslint_warning.png" class="kg-image" alt="eslint_warning" width="600" height="400" loading="lazy"></figure><p>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.</p><p>Como estamos haciendo referencia al estado de <code>users</code> dentro de la función <code>loadUsers</code>, debemos incluirlo también en en arreglo de dependencia. Así que hagámoslo.</p><p>Incluye a los <code>users</code> como una dependencia junto con <code>page</code> como se muestra a continuación:</p><pre><code class="language-js">useEffect(() =&gt; {
  // your code
}, [page, users]);
</code></pre><p>Comprobemos ahora la funcionalidad de la aplicación.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/infinite_loop.gif" class="kg-image" alt="infinite_loop" width="600" height="400" loading="lazy"></figure><p>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.</p><p>Esto se debe a que cuando se monta el componente, el código dentro del hook <code>useEffect</code> se ejecutará para realizar una llamada al API. Una vez que obtenemos el resultado, configuramos el arreglo de <code>users</code>.</p><p>Como los <code>users</code> son mencionados en la lista de dependencias, una vez que se cambia el arreglo de usuarios, <code>useEffect</code> se ejecutará nuevamente y sucederá una y otra vez creando un bucle infinito.</p><p>Entonces, para solucionar esto, debemos evitar hacer referencia al arreglo de <code>users</code> externos de alguna manera. Para hacer eso, usemos la sintaxis del actualizador de <code>setState</code> para configurar el estado de <code>users</code>.</p><p>Por lo tanto, cambia el siguiente código:</p><pre><code class="language-js">setUsers([...users, ...response.data.results]);
</code></pre><p>a este código:</p><pre><code class="language-js">setUsers((users) =&gt; [...users, ...response.data.results]);
</code></pre><p>Aquí, estamos usando el valor anterior de <code>users</code> para crear un nuevo arreglo de <code>users</code>.</p><p>Ahora, podemos eliminar los <code>users</code> del arreglo de dependencias de <code>useEffect</code> ya que no estamos haciendo referencia a la variable externa <code>users</code>.</p><p>Tu hook <code>useEffect</code> modificado se verá así ahora:</p><pre><code class="language-js">useEffect(() =&gt; {
  const loadUsers = async () =&gt; {
    try {
      setIsLoading(true);
      const response = await axios.get(
        `https://randomuser.me/api/?page=${page}&amp;results=10`
      );

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

  loadUsers();
}, [page]);
</code></pre><p>Si revisas la aplicación ahora, verás funciona como se esperaba sin ningún problema.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/correct_loading-3.gif" class="kg-image" alt="correct_loading-3" width="600" height="400" loading="lazy"></figure><p>Y ahora tampoco estamos recibiendo ningún error en la terminal.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/no_error.png" class="kg-image" alt="no_error" width="600" height="400" loading="lazy"></figure><h3 id="-gracias-por-leer-"><strong>¡Gracias por leer!</strong></h3><p>Puedes encontrar el código fuente completo para esta aplicación en <a href="https://github.com/myogeshchavan97/class-to-hooks-refactoring">este repositorio</a> y una demostración en vivo de la aplicación implementada <a href="https://random-users-app.netlify.app/">aquí</a>.</p><p>Traducido del artículo de<strong> <a href="https://www.freecodecamp.org/news/build-a-react-application-with-load-more-functionality-react-hooks/">Yogesh Chavan - How to Build a React Application with Load More Functionality using React Hooks</a></strong><br></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Aprende Git y control de versiones en una hora ]]>
                </title>
                <description>
                    <![CDATA[ El control de versiones es algo que todos los desarrolladores de software deberían conocer. Te ayuda a administrar los cambios en tus proyectos o programas. Este artículo te ayudará a aprender los conceptos básicos de Git y el control de versiones para colaborar y administrar de manera efectiva sus proyectos ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/aprende-git-y-control-de-versiones-en-una-hora/</link>
                <guid isPermaLink="false">60561afe540cd708b5737cbb</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Juan C. Guaña ]]>
                </dc:creator>
                <pubDate>Fri, 21 May 2021 03:48:18 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/03/photo-1534988333262-c455b9332e52.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>El control de versiones es algo que todos los desarrolladores de software deberían conocer. Te ayuda a administrar los cambios en tus proyectos o programas.</p><p>Este artículo te ayudará a aprender los conceptos básicos de Git y el control de versiones para colaborar y administrar de manera efectiva sus proyectos de software.</p><h2 id="contenido"><strong>Contenido</strong></h2><ul><li><a href="#-qu-son-git-y-control-de-versiones">¿Qué son Git y control de versiones?</a></li><li><a href="#configurando-tu-git-bash">Configurando tu Git bash</a></li><li><a href="#inicializando-tu-repositorio">Inicializando tu repositorio</a></li><li><a href="#haciendo-tu-primer-commit-en-git">Haciendo tu primer commit en Git</a></li><li><a href="#creando-una-rama-branch-en-git">Creando una rama (branch) en Git</a></li><li><a href="#regresando-a-un-commit">Regresando a un commit</a></li><li><a href="#creando-un-repositorio-remoto">Creando un repositorio remoto</a></li><li><a href="#sincronizando-tu-repositorio-remoto-con-tu-repositorio-local">Sincronizando tu repositorio remoto con tu repositorio local</a></li><li><a href="#actualizando-tu-repositorio-de-git-local-y-remoto-">Actualizando tu repositorio de Git (local y remoto)</a></li><li><a href="#-qu-significa-origin">¿Qué significa "origin"?</a></li></ul><h2 id="pre-requisitos"><strong>Pre-</strong>requisitos</h2><p>Supongo que ya tienes una cuenta en GitHub. Si no es así, dirígete a la página de <a href="https://github.com/">GitHub</a> para crear una.</p><p>También necesitarás descargar e instalar Git bash desde <a href="https://www.freecodecamp.org/espanol/news/p/2d7ea7a0-18ec-43ff-88e0-fdd581f41e75/git-scm.com">git-scm.com</a> o <a href="https://www.freecodecamp.org/espanol/news/p/2d7ea7a0-18ec-43ff-88e0-fdd581f41e75/gitforwindows.org">gitforwindows.org</a> (si trabajas en una PC con Windows).</p><p>Ahora sigamos adelante y aprendamos sobre el control de versiones.</p><h2 id="-qu-son-git-y-control-de-versiones">¿Qué son Git y control de versiones?</h2><p>Git es un sistema de control de versiones que se utiliza para dar seguimiento a los cambios que se realizan en un archivo o proyecto. Fue hecho por Linus Trovalds (el creador del sistema operativo Linux).</p><p>GitHub, por otro lado, es una plataforma de colaboración de código abierto basada en la nube que permite a los desarrolladores compartir software fácilmente y colaborar en diferentes proyectos.</p><p>Todos, desde proyectos de código abierto hasta equipos privados y proyectos individuales, puede utilizar GitHub. Sólo tienes que subir tu código y hacer un seguimiento de los cambios realizados en un proyecto para su uso futuro.</p><p><strong>Resumiendo: </strong>El control de versiones es un sistema que registra los cambios en un archivo o conjunto de archivos a lo largo del tiempo para que pueda recuperar versiones específicas más adelante.</p><h2 id="configurando-tu-git-bash">Configurando tu Git bash</h2><p>Para el propósito de este tutorial, crearemos una nueva carpeta llamada <code>primerospasosgit</code>. La usaremos como nuestro repositorio local a lo largo de este artículo.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-1.png" class="kg-image" alt="image-1" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2021/03/image-1.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-1.png 657w" width="657" height="159" loading="lazy"><figcaption>Una nueva carpeta creada solo para este tutorial de Git</figcaption></figure><p>Dentro de esta carpeta <code>primerospasosgit</code>, tenemos un archivo, <code>index.html</code>, que usaremos para las instancias. Lo puedes crear desde la línea de comandos o editor de texto favorito.</p><p>Puedes crear el tuyo escribiendo <code>touch index.html</code> dentro de la carpeta <code>primerospasosgit</code> (esto lo debes hacer desde Git bash) o puedes crear uno desde tu editor de texto.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-6.png" class="kg-image" alt="image-6" width="467" height="50" loading="lazy"><figcaption>Un nuevo archivo creado solo para este tutorial de Git</figcaption></figure><p>Ahora, preparemos nuestro entorno global de Git configurando nuestro nombre de usuario y correo electrónico (si es la primera vez que usas Git).</p><p>Abre Git bash, luego usa el comando <strong><strong><code>git config --global user.name "</code></strong><code>Tu nombre "</code></strong> para configurar tu nombre de usuario y <strong><strong><code>git config --global user.email "</code></strong><code>Tu correo electrónico</code><strong><code>"</code></strong></strong> para configurar tu correo electrónico.</p><p>En la siguiente instancia, mi nombre de usuario de GitHub es <code>JuanGuana</code>, mientras que mi dirección de correo electrónico es <code>juanc.guana@gmail.com</code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-4.png" class="kg-image" alt="image-4" width="508" height="98" loading="lazy"><figcaption>Configurando Git en tu dispositivo</figcaption></figure><p>Para verificar si tu configuración ha sido agregada, escribe <code><strong>git config --global user.name</strong></code> para verificar tu nombre de usuario y <code><strong>git config --global user.email</strong></code> para verificar tu correo electrónico.</p><p>Si tu configuración fue exitosa, se mostrará tu nombre de usuario y dirección de correo electrónico una vez que ingreses estos comandos y presiones <em>enter</em>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-5.png" class="kg-image" alt="image-5" width="342" height="129" loading="lazy"><figcaption>Comprobando tu configuración</figcaption></figure><h2 id="inicializando-tu-repositorio">Inicializando tu repositorio</h2><p>Ahora querrás decirle a Git "Mira, esta es la carpeta o directorio donde quiero que Git trabaje en este momento".</p><p>Para inicializar un repositorio, asegúrese de estar en el directorio en el que estás trabajando. En mi caso aquí, es la carpeta <code>primerospasosgit</code>.</p><p>Luego escribe <code><strong>git init</strong></code> y presiona enter.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-7.png" class="kg-image" alt="image-7" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2021/03/image-7.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-7.png 759w" sizes="(min-width: 720px) 720px" width="759" height="216" loading="lazy"><figcaption>Inicializando Git en la carpeta primerospasosgit</figcaption></figure><h2 id="haciendo-tu-primer-commit-en-git">Haciendo tu primer commit en Git</h2><p>Hacer commit en Git es el equivalente a guardar cuando se trabaja en documentos. Es una forma de guardar la versión del documento, es decir, los cambios realizados en el repositorio y almacenarlos con una ID único y un mensaje.</p><p>El ID y el mensaje se pueden usar para rastrear la versión del proyecto que necesitas verificar. Esta es una de las diferencias entre <code><strong>git commit</strong></code> y <code>guardar como</code>.</p><p>Antes de hacer un commit, debes mandar los cambios en tu proyecto al área de <strong>staging</strong>. El staging es una forma de decirle al sistema: "Oye, hice muchos cambios en mi trabajo, pero éste, aquél y este otro son los que quiero guardar".</p><p>Entonces, cuando queremos enviar nuestros cambios a esta área, usamos el siguiente comando: <code><strong>git add nombre-de-los-archivos</strong></code>.</p><p>Si quieres agregar todos los archivos que se realizaron cambios, escribe <code><strong>git add .</strong></code> en su lugar. Solo asegúrate de estar dentro de la carpeta del proyecto.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-8.png" class="kg-image" alt="image-8" width="545" height="47" loading="lazy"><figcaption>Añadiendo archivo al área de staging</figcaption></figure><p>Después de agregar los archivos al área de staging, ahora puedes guardar tus cambios con un commit.</p><p>Debes hacer un commit de tus cambios utilizando mensajes de confirmación cortos pero detallados de esta manera: <code><strong>git commit -m "Tu mensaje corto"</strong></code></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-9.png" class="kg-image" alt="image-9" width="555" height="144" loading="lazy"><figcaption>Guardando los cambios con commit en Git</figcaption></figure><p>Para ver el estado de tu repositorio, saber en qué rama se encuentra, que archivos se modificaron, si el código está listo o no en el staging antes de hacer commit, simplemente usa el código: <code>git status</code>.</p><h2 id="creando-una-rama-branch-en-git">Creando una rama (branch) en Git</h2><p>Digamos que estás trabajando en diferentes versiones de un proyecto o estás colaborando en un proyecto con algunos amigos o colegas. Es importante tener una rama llamada "master", que es la rama predeterminada para cada repositorio local, que almacena el código original y modificado de varios colaboradores.</p><p>Para colaborar o trabajar en varias versiones de un proyecto, tenemos que trabajar desde diferentes ramas.</p><p>Al trabajar en ramas, no solo es posible trabajar en múltiples versiones del código en paralelo, sino que también mantiene la rama principal libre de código cuestionable.</p><p>Entonces, para nuestro proyecto <code>primerospasosgit</code>, podemos tener varias ramas, cada una con una versión diferente del código.</p><p>Para crear una nueva rama en Git, usa el comando <code><strong>git branch nombre-de-la-rama</strong></code>.</p><p>Para revisar o cambiarse a la nueva rama, usa <code><strong>git checkout nombre-de-la-rama</strong></code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-10.png" class="kg-image" alt="image-10" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2021/03/image-10.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-10.png 653w" width="653" height="173" loading="lazy"><figcaption>Creando ramas en Git</figcaption></figure><p>Los 2 comandos anteriores se pueden realizar simultáneamente con el comando: <code><strong>git checkout -b nombre-de-otra-rama</strong></code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-11.png" class="kg-image" alt="image-11" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2021/03/image-11.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-11.png 663w" width="663" height="109" loading="lazy"><figcaption>Creando y cambiando de ramas en Git</figcaption></figure><h2 id="regresando-a-un-commit">Regresando a un commit</h2><p>Aquí viene otra cosa muy interesante sobre Git: la capacidad de revertir los cambios que ha realizado con el tiempo, algo que CTRL + Z no puede hacer.</p><p>Mientras trabajamos con Git, es posible que quieras volver a un estado particular de tu código, o incluso volver a una versión anterior de tu trabajo. Puedes hacer esto volviendo a un commit en particular.</p><p>Cada commit que hacemos tiene un ID único adjunto. Para obtener este ID, puedes escribir <code><strong>git log</strong></code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-12.png" class="kg-image" alt="image-12" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2021/03/image-12.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-12.png 948w" sizes="(min-width: 720px) 720px" width="948" height="189" loading="lazy"><figcaption>Log de Git</figcaption></figure><p>Alternativamente, la salida anterior se puede registrar en una línea usando <code><strong>git log --oneline</strong></code>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-13.png" class="kg-image" alt="image-13" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2021/03/image-13.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-13.png 770w" sizes="(min-width: 720px) 720px" width="770" height="67" loading="lazy"><figcaption>Log de Git en una linea</figcaption></figure><p>De lo anterior, puedes ver el ID y los mensajes para cada uno de los commits.</p><p>Para regresar a un commit anterior, escribe <code><strong>git revert commit-ID</strong></code>.</p><p>Este comando regresa al estado de ese código en el momento de ese commit.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-14.png" class="kg-image" alt="image-14" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2021/03/image-14.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-14.png 669w" width="669" height="193" loading="lazy"><figcaption>Regresando a un commit anterior</figcaption></figure><h2 id="creando-un-repositorio-remoto">Creando un repositorio remoto</h2><p>Para crear un repositorio remoto, abriremos nuestra cuenta de GitHub y haremos clic en el botón <strong>New</strong> (como usuario de GitHub por primera vez, probablemente verás el botón verde <strong><strong>Create Repository</strong></strong> en su lugar).</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-15.png" class="kg-image" alt="image-15" width="387" height="127" loading="lazy"><figcaption>Creando un nuevo repositorio remoto</figcaption></figure><p>De cualquier manera que lo hagas, te llevará a la página donde ingresas el nombre de su repositorio y una descripción de tu proyecto.</p><p>También te da la opción de hacer que tu repositorio sea privado o público. Puedes inicializar tu repositorio con un archivo <em>README </em>marcando la casilla de verificación.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-16.png" class="kg-image" alt="image-16" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2021/03/image-16.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-16.png 888w" sizes="(min-width: 720px) 720px" width="888" height="887" loading="lazy"><figcaption>Creando un repositorio remoto en GitHub</figcaption></figure><p>Al hacer clic en <strong>Create repository</strong>, se creará un nuevo repositorio con una URL única.</p><h2 id="sincronizando-tu-repositorio-remoto-con-tu-repositorio-local">Sincronizando tu repositorio remoto con tu repositorio local</h2><p>Ahora que hemos creado nuestro repositorio remoto, tenemos que sincronizarlo con nuestro repositorio local para que ambos puedan comunicarse sin problemas.</p><p>GitHub nos ayuda a cargar un repositorio local de diferentes maneras, en nuestro caso utilizaremos las siguientes indicaciones.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-17.png" class="kg-image" alt="image-17" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2021/03/image-17.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-17.png 714w" width="714" height="139" loading="lazy"><figcaption>Instrucciones de GitHub</figcaption></figure><p>Abre tu Git bash, navega hasta la carpeta en la que estás trabajando e ingresa las líneas de código indicadas por GitHub.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-18.png" class="kg-image" alt="image-18" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2021/03/image-18.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-18.png 662w" width="662" height="314" loading="lazy"><figcaption>Cargando el repositorio local en el repositorio remoto</figcaption></figure><p>Desde hace un tiempo la rama principal en GitHub tuvo un cambio y paso de llamarse "master" a "main".</p><h2 id="actualizando-tu-repositorio-de-git-local-y-remoto-">Actualizando tu repositorio de Git (local y remoto)</h2><p>Sigamos adelante y agreguemos algo de código a nuestro archivo HTML:</p><pre><code class="language-js">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8" /&gt;
    &lt;meta http-equiv="X-UA-Compatible" content="IE=edge" /&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
    &lt;title&gt;Document&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;label for="inputEmail" class="sr-only"&gt;Correo Electrónico&lt;/label&gt;
    &lt;input
      type="email"
      class="form-control"
      id="inputEmail"
      placeholder="Contraseña"
    /&gt;
  &lt;/body&gt;
&lt;/html&gt;               </code></pre><p>Repitamos el proceso de enviar nuestros cambios a staging y guardar nuestros cambios con un commit: <code><strong>git add index.html</strong></code>‌‌, <code><strong>git commit -m "formulario agregado"</strong></code></p><p>En este momento, nuestro repositorio local está un commit por delante del repositorio remoto.</p><p>Para actualizar el repositorio remoto, tendremos que enviar nuestro trabajo desde el repositorio local al repositorio remoto usando el comando: <code><strong>git push origin main</strong></code>, "main" es la rama predeterminada para cada repositorio remoto y la mayoría de las veces alberga el código principal del proyecto</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-19.png" class="kg-image" alt="image-19" width="545" height="363" loading="lazy"><figcaption>Agregando cambios en nuestro repositorio</figcaption></figure><p>También puedes optar por crear o modificar una rama si, por ejemplo, creaste una nueva función, pero te preocupa realizar cambios en el proyecto principal.‌‌</p><p>Siempre puedes usar <code><strong>git branch</strong></code> para confirmar las ramas en este repositorio. El nombre de la rama con asterisco al lado indica a qué rama está apuntado en un momento dado.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-20.png" class="kg-image" alt="image-20" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2021/03/image-20.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-20.png 650w" width="650" height="322" loading="lazy"><figcaption>Listando las ramas del repositorio</figcaption></figure><p>También puedes enviar cambios desde otra rama a tu repositorio remoto con <code><strong>git push origin nombre-de-la-rama</strong></code>.</p><p>Cuando envías tus cambios al repositorio remoto, GitHub creará automáticamente la rama por ti en tu repositorio remoto. Esto permite que las personas vean los cambios que has realizado.</p><p>También es posible que quieras actualizar alguna rama con el contenido de alguna rama remota.</p><p>Puedes hacer esto cambiándote a la rama deseada y ejecutando <code><strong>git pull origin main</strong></code>. Esto actualiza la rama actual con todos los cambios implementados en la rama remota.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-21.png" class="kg-image" alt="image-21" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2021/03/image-21.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2021/03/image-21.png 649w" width="649" height="190" loading="lazy"><figcaption>Actualizando la rama local con cambios en la rama remota</figcaption></figure><h2 id="-qu-significa-origin">¿Qué significa "origin"?</h2><p>Origin es un nombre abreviado para el repositorio remoto desde el que se clonó originalmente un proyecto. Más precisamente, se utiliza en lugar de la URL del repositorio original y facilita su referencia.</p><p>Entonces, para enviar los cambios al repositorio remoto, puedes usar cualquiera de los siguientes comandos: <code><strong>git push origin nombre-de-la-rama</strong></code> o <code><strong>git push https://github.com/nombre-de-usuario/nombre-del-repositorio.git nombre-de-la-rama‌‌</strong></code>.</p><p>Ten en cuenta que te puede solicitar que ingreses tu nombre de usuario y contraseña. Tu contraseña no se mostrará cuando la ingrese. Simplemente escríbelo correctamente y presione <em>enter</em>.</p><h2 id="conclusi-n">Conclusión</h2><p>Acabamos de ver una guía paso a paso para usar Git por primera vez. No dudes en consultarlo cuando te quedes atascado.</p><p>No es necesario que memorices los comandos; podrá recordarlos con el tiempo. :)</p><p>‌¡Eso es todo por ahora!</p><p>Traducido del artículo de <a href="https://www.freecodecamp.org/news/author/amarachukwu/"><strong>Amarachi Emmanuela Azubuike</strong></a><a href="#https://www.freecodecamp.org/news/learn-git-and-version-control-in-an-hour/"><strong><strong> </strong></strong></a><strong> - </strong><a href="#https://www.freecodecamp.org/news/learn-git-and-version-control-in-an-hour/"><strong>Learn Git and Version Control in an Hour</strong></a></p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
