<?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[ Vanessa Pineiro Morales - 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[ Vanessa Pineiro Morales - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/espanol/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 31 May 2026 04:47:21 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/espanol/news/author/vanessa-pineiro-morales/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Cómo Escribir una Promesa JavaScript ]]>
                </title>
                <description>
                    <![CDATA[ ¿Qué es una promesa? Una promesa de JavaScript es un objeto que representa la finalización o falla de una tarea asíncrona y su valor resultante.¹ El fin. Estoy bromeando, por supuesto. Entonces, ¿qué significa esa definición? En primer lugar, muchas cosas en JavaScript son objetos. Puedes crear un objeto de ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-escribir-una-promesa-de-javascript/</link>
                <guid isPermaLink="false">644ee428e59d8f07c2db32a1</guid>
                
                    <category>
                        <![CDATA[ Programación ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vanessa Pineiro Morales ]]>
                </dc:creator>
                <pubDate>Sat, 06 May 2023 00:46:27 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/04/1-RR8oubeQOm63YN90Uth0CA.jpeg" 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-write-a-javascript-promise-4ed8d44292b8/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Write a JavaScript Promise</a>
      </p><h2 id="-qu-es-una-promesa">¿Qué es una promesa?</h2><p>Una promesa de JavaScript es un objeto que representa la finalización o falla de una tarea asíncrona y su valor resultante.¹</p><p>El fin.</p><p>Estoy bromeando, por supuesto. Entonces, ¿qué significa esa definición?</p><p>En primer lugar, muchas cosas en JavaScript son objetos. Puedes crear un objeto de diferentes maneras. La forma más común es con sintaxis literal de objeto:</p><pre><code class="language-js">const miCarro = {
   color: 'azul',
   tipo: 'sedán',
   puertas: '4',
};</code></pre><p>También puedes crear un <code>class</code> e instanciarla con la palabra clave <code>new</code>.</p><pre><code class="language-js">class Carro {
   constructor(color, tipo, puertas) {
      this.color = color;
      this.tipo = tipo;
      this.puertas = puertas
   }
}

const miCarro = new Carro('azul', 'sedán', '4');</code></pre><p><code>console.log(miCarro);</code></p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*QUB10cb7QMBVBEGM2JRo1g.png" class="kg-image" alt="1*QUB10cb7QMBVBEGM2JRo1g" width="636" height="166" loading="lazy"></figure><p>Una promesa es simplemente un objeto como el que creamos con el último ejemplo. Lo instanciamos con la palabra clave <code>new</code>. En lugar de los tres parámetros que pasamos para hacer nuestro auto (color, tipo y puertas), pasamos una función que toma dos argumentos: <code>resolve</code> y <code>reject</code>.</p><p>En última instancia, las promesas nos dicen algo sobre la finalización de la función asíncrona de la que la devolvimos–si funcionó o no. Decimos que la función tuvo éxito al decir que la promesa se <em>resolvió</em>, y que no tuvo éxito al decir que la promesa se <em>rechazó</em>.</p><pre><code class="language-js">const myPromesa = new Promesa(function(resolve, reject) {});</code></pre><p><code>console.log(myPromesa);</code></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/1*z8UFY0q1iVmr4xzOqOvFlA.png" class="kg-image" alt="1*z8UFY0q1iVmr4xzOqOvFlA" width="518" height="140" loading="lazy"><figcaption>Observe que la promesa está pendiente ("pending").</figcaption></figure><pre><code class="language-js">const myPromesa = new Promesa(function(resolve, reject) {
   resolve(10);
});</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/1*voamRd9sJg_NZ0vOdbYJgg.png" class="kg-image" alt="1*voamRd9sJg_NZ0vOdbYJgg" width="516" height="134" loading="lazy"><figcaption>Observe que resolvimos la promesa con el valor 10.</figcaption></figure><p>Vez, no es demasiado aterrador, solo un objeto que creamos. Y, si lo ampliamos un poco:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/1*szpVAwKfKzMasjP9Wlpigg.png" class="kg-image" alt="1*szpVAwKfKzMasjP9Wlpigg" width="596" height="320" loading="lazy"><figcaption>Observe que tenemos algunos métodos a los que tenemos acceso, "then" y "catch"</figcaption></figure><p>Además, podemos pasar cualquier cosa que nos gustaría a resolve y reject. Por ejemplo, podríamos pasar un objeto en lugar de una cadena:</p><pre><code class="language-js">return new Promesa((resolve, reject) =&gt; {
   if(algoExitosoPasó) {
      const objetoDeÉxito = {
         msg: 'Éxito',
         data,//...algunos datos que obtuvimos
      }
      resolve(objetoDeÉxito); 
   } else {
      const objetoDeError = {
         msg: 'Ocurrió un error',
         error, //...algún error que recibimos
      }
      reject(objetoDeError);
   }
});</code></pre><p>O, como vimos antes, no tenemos que pasar nada:</p><pre><code class="language-js">return new Promesa((resolve, reject) =&gt; {
   if(algoExitosoPasó) {
      resolve()
   } else {
      reject();
   }
});</code></pre><h3 id="-qu-pasa-con-la-parte-asincr-nica-de-la-definici-n"><strong>¿Qué pasa con la parte "asincrónica" de la definición?</strong></h3><p>JavaScript es de un solo subproceso. Esto significa que solo puede ejecutar una cosa a la vez. Si puedes imaginar una carretera, puedes pensar en JavaScript como una autopista de un solo carril. Cierto código (código asíncrono) puede deslizarse hacia el hombro para permitir que otro código lo pase. Cuando se realiza ese código asíncrono, vuelve a la carretera.</p><blockquote>Como nota al margen, podemos devolver una promesa desde <em>cualquier</em> función. No tiene que ser asíncrono. Dicho esto, las promesas normalmente se devuelven en los casos en que la función de la que devuelven es asíncrona. Por ejemplo, un API que tiene métodos para guardar datos en un servidor sería un gran candidato para devolver una promesa.</blockquote><h3 id="la-conclusi-n-">La conclusión:</h3><p>Las promesas nos brindan una forma de esperar a que se complete nuestro código asíncrono, capturar algunos valores de él y pasar esos valores a otras partes de nuestro programa.</p><h3 id="-c-mo-usamos-una-promesa"><strong>¿Cómo usamos una promesa?</strong></h3><p>El uso de una promesa también se llama <em>consumir</em> una promesa. En nuestro ejemplo anterior, nuestra función devuelve un objeto de promesa. Esto nos permite usar el encadenamiento de métodos con nuestra función.</p><p>Aquí hay un ejemplo de encadenamiento de métodos que apuesto a que no has visto:</p><pre><code class="language-js">const a = 'Una cadena impresionante';
const b = a.toUpperCase().replace('CA', '').toLowerCase();

console.log(b); // una dena impresionante
</code></pre><p>Ahora, recuerda nuestra (pretendida) promesa:</p><pre><code class="language-js">const algoFueExitoso = true;

function algunaFunciónAsíncrona() {
   return new Promesa((resolve, reject){
      if (algoFueExitoso) {
         resolve();     
      } else {
         reject()
      }
   });
}</code></pre><p>Y, consumiendo nuestra promesa usando el encadenamiento de métodos:</p><pre><code class="language-js">algunaFunciónAsíncrona
   .then(ejecutarUnaFunciónSiSeResuelve(conElValorResuelto))
   .catch(oEjecutarUnaFunciónSiEsRechazada(conElValorRechazado));</code></pre><h3 id="un-ejemplo-m-s-real-"><strong>Un ejemplo (más) real.</strong></h3><p>Imagina que tienes una función que obtiene usuarios de una base de datos. He escrito una función de ejemplo en Codepen que simula una API que podrías usar. Proporciona dos opciones para acceder a los resultados. Uno, puede proporcionar una función de retrollamada donde puede acceder al usuario o cualquier error. O dos, la función devuelve una promesa como una forma de acceder al usuario o error.</p><figure class="kg-card kg-embed-card"><iframe id="cp_embed_NoNMgJ" src="https://codepen.io/brandonwoz/embed/preview/NoNMgJ?height=300&amp;slug-hash=NoNMgJ&amp;default-tabs=js,result&amp;host=https://codepen.io" title="Embedded content" scrolling="no" frameborder="0" height="300" allowtransparency="true" class="cp_embed_iframe" loading="lazy" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size-adjust: inherit; font-kerning: inherit; font-variant-alternates: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-position: inherit; font-feature-settings: inherit; font-optical-sizing: inherit; font-variation-settings: inherit; font-size: 22px; vertical-align: middle; width: 720px; overflow: hidden;"></iframe></figure><p>Tradicionalmente, accederíamos a los resultados del código asíncrono mediante el uso de retrollamadas.</p><pre><code class="language-js">rr algoDeBaseDeDatos(talVezUnID, function(err, result)) {
   //...Una vez que recuperemos la cosa de la base de datos...
   if(err) {
      hacerAlgoConElError(error)
   }   else {
      hacerAlgoConLosResultados(results);
   }
}</code></pre><p>El uso de retrollamada está <em>bien</em> hasta que se anidan demasiado. En otras palabras, tiene que ejecutar más código asincrónico con cada nuevo resultado. Este patrón de retrollamada dentro de las retrollamadas puede conducir a algo conocido como "infierno de retrollamada".</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/1*DxEgvtymVuqpLOSx8NJ57A.png" class="kg-image" alt="1*DxEgvtymVuqpLOSx8NJ57A" width="800" height="312" loading="lazy"><figcaption>Los comienzos del infierno de retrollamada</figcaption></figure><p>Las promesas nos ofrecen una forma más elegante y legible de ver el flujo de nuestro programa.</p><pre><code class="language-js">hazAlgo()
   .then(hacerAlgoMás) // y si no te importa
   .catch(cualquierErrorPorFavor);</code></pre><h3 id="escribiendo-nuestra-propia-promesa-ricitos-de-oro-los-tres-osos-y-una-supercomputadora"><strong>Escribiendo nuestra propia promesa: Ricitos de Oro, los Tres Osos y una Supercomputadora</strong></h3><p>Imagina que encuentras un plato de sopa. Te gustaría saber la temperatura de esa sopa antes de comerla. No te quedan termómetros, pero por suerte tienes acceso a una supercomputadora que te dice la temperatura del plato de sopa. Desafortunadamente, esta supercomputadora puede tardar hasta 10 segundos en obtener los resultados.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*XtBW084Eg2feXeR97W2yvw.png" class="kg-image" alt="1*XtBW084Eg2feXeR97W2yvw" width="800" height="405" loading="lazy"></figure><p>Aquí hay un par de cosas para notar.</p><ol><li>Iniciamos una variable global llamado <code>result</code>.</li><li>Simulamos la duración del retraso de la red con <code>Math.random()</code> y <code>setTimeout()</code>.</li><li>Simulamos una temperatura con <code>Math.random()</code>.</li><li>Mantenemos los valores de retardo y temperatura confinados dentro de un rango agregando algunas "matemáticas" adicionales. El rango de <code>temp</code> es de 1 a 300; el rango de <code>delay</code> es de 1000 ms a 10000 ms (1s a 10 segundos).</li><li>Registramos el retraso y la temperatura para tener una idea de cuánto tiempo llevará esta función y los resultados que esperamos ver cuando esté lista.</li></ol><p>Ejecute la función y registre los resultados.</p><pre><code class="language-js">getTemperature(); 
console.log(results); // undefined (indefinido)</code></pre><h3 id="la-temperatura-no-est-definida-qu-pas-"><strong>La temperatura no está definida. ¿Qué pasó?</strong></h3><p>La función tardará un cierto tiempo en ejecutarse. El variable no se establece hasta que finaliza el retraso. Entonces, mientras ejecutamos la función, <code>setTimeout</code> es asíncrono. La parte del código en <code>setTimeout</code> sale del subproceso principal hacia un área de espera.</p><p>Dado que la parte de nuestra función que establece el variable de <code>result</code> se mueve a un área de espera hasta que finaliza, nuestro analizador puede pasar a la siguiente línea. En nuestro caso, es nuestro <code>console.log()</code>. En este punto, el <code>result</code> aún no está definido, ya que nuestro <code>setTimeout</code> no ha terminado.</p><p>Entonces, ¿qué más podríamos intentar? Podríamos ejecutar <code>getTemperature()</code> y luego esperar 11 segundos (ya que nuestro retraso máximo es de diez segundos) y <em>luego</em> console.log los resultados.</p><pre><code class="language-js">getTemperature();
   setTimeout(() =&gt; {
      console.log(result); 
   }, 11000);
   
// Too Hot | Delay: 3323 | Temperature: 209 deg</code></pre><p>Esto funciona, pero el problema con esta técnica es que, aunque en nuestro ejemplo conocemos el retraso máximo de la red, en un ejemplo de la vida real, en ocasiones puede tardar más de diez segundos. Y, aunque pudiéramos garantizar un retraso máximo de diez segundos, si el resultado está listo antes, estamos perdiendo el tiempo.</p><h3 id="promesas-al-rescate"><strong>Promesas al Rescate</strong></h3><p>Vamos a refactorizar nuestra función <code>getTemperature()</code> para devolver una promesa. Y en lugar de establecer el resultado, rechazaremos la promesa a menos que el resultado sea "Exacto", en cuyo caso resolveremos la promesa. En cualquier caso, pasaremos algunos valores para resolver y rechazar.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*4RJERRgVUtHlIYRFm2piVQ.png" class="kg-image" alt="1*4RJERRgVUtHlIYRFm2piVQ" width="800" height="432" loading="lazy"></figure><p>Ahora podemos usar los resultados de nuestra promesa que estamos devolviendo (también conocido como <em>consumir </em>la promesa).</p><pre><code class="language-js">getTemperature()
   .then(result =&gt; console.log(result))
   .catch(error =&gt; console.log(error));
   
// Reject: Too Cold | Delay: 7880 | Temperature: 43 deg</code></pre><p><code>.then</code> será llamado cuando nuestra promesa se resuelva y devolverá cualquier información que pasemos a <code>resolve</code>.</p><p>Se llamará a <code>.catch</code> cuando nuestra promesa se rechace y devolverá cualquier información que pasemos al <code>reject</code>.</p><p>Lo más probable es que consumas más promesas de lo que las creas. En cualquier caso, ayudan a que nuestro código sea más elegante, legible y eficiente.</p><h3 id="resumen"><strong>Resumen</strong></h3><ol><li>Las promesas son objetos que contienen información sobre la finalización de algún código asíncrono y los valores resultantes que queremos pasar.</li><li>Para devolver una promesa usamos <code>return new Promise((resolve, reject)=&gt; {})</code></li><li>Para consumir una promesa usamos <code>.then</code> para obtener la información de una promesa que se ha resuelto y <code>.catch</code> para obtener la información de una promesa que se ha rechazado.</li><li>Probablemente, usarás (consumirás) promesas más de lo que escribirás.</li></ol><h3 id="referencias"><strong>Referencias</strong></h3><p>1.)<a href="https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Promise">https://developer.mozilla.org/es/docs/Web/JavaScript/Reference/Global_Objects/Promise</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo construir un chatbot de Discord con AI que hable como tu personaje favorito ]]>
                </title>
                <description>
                    <![CDATA[ ¿Te gustaría hablar con un chatbot que hable como tu personaje favorito, ficticio o no? ¡Construyamos uno! En caso de que hayas visto mi tutorial anterior sobre este tema, quédese conmigo, ya que esta versión presenta muchas actualizaciones. Puedes seguir este tutorial usando el código en mi GitHub: GitHub - ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-construir-un-discord-ai-chatbot-que-habla-como-tu-personaje-favorito/</link>
                <guid isPermaLink="false">644ecbd8e59d8f07c2db313b</guid>
                
                    <category>
                        <![CDATA[ inteligencia artificial ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vanessa Pineiro Morales ]]>
                </dc:creator>
                <pubDate>Fri, 05 May 2023 18:36:54 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/04/lynns-thumbnail.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/discord-ai-chatbot/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Build a Discord AI Chatbot that Talks Like Your Favorite Character</a>
      </p><p>¿Te gustaría hablar con un chatbot que hable como tu personaje favorito, ficticio o no? ¡Construyamos uno!</p><p>En caso de que hayas visto mi tutorial anterior sobre este tema, quédese conmigo, ya que esta versión presenta muchas actualizaciones.</p><p>Puedes seguir este tutorial usando el código en mi GitHub:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://github.com/RuolinZheng08/twewy-discord-chatbot"><div class="kg-bookmark-content"><div class="kg-bookmark-title">GitHub - RuolinZheng08/twewy-discord-chatbot: Discord AI Chatbot using DialoGPT, trained on the game transcript of The World Ends With You</div><div class="kg-bookmark-description">Discord AI Chatbot using DialoGPT, trained on the game transcript of The World Ends With You - GitHub - RuolinZheng08/twewy-discord-chatbot: Discord AI Chatbot using DialoGPT, trained on the game t...</div><div class="kg-bookmark-metadata"><img class="kg-bookmark-icon" src="https://github.githubassets.com/favicons/favicon.svg" width="32" height="32" alt="favicon" loading="lazy"><span class="kg-bookmark-author">GitHub</span><span class="kg-bookmark-publisher">RuolinZheng08</span></div></div><div class="kg-bookmark-thumbnail"><img src="https://opengraph.githubassets.com/8dca0d6ce6fc7396c368f60cb856a1843afd7bb35792fa1fd7844eb3b55e14d0/RuolinZheng08/twewy-discord-chatbot" width="1200" height="600" alt="twewy-discord-chatbot" loading="lazy"></div></a></figure><p>Si lo desea, puede sumergirse directamente en mi videotutorial en YouTube, o seguir leyendo para obtener más detalles. ?</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.178385416666664%;" class="fluid-width-video-wrapper">
            <iframe src="https://www.youtube.com/embed/Rk8eM1p_xgM?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen="" title="Embedded content" loading="lazy" name="fitvid0" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant-caps: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size-adjust: inherit; font-kerning: inherit; font-variant-alternates: inherit; font-variant-ligatures: inherit; font-variant-numeric: inherit; font-variant-east-asian: inherit; font-variant-position: inherit; font-feature-settings: inherit; font-optical-sizing: inherit; font-variation-settings: inherit; font-size: 22px; vertical-align: middle; position: absolute; top: 0px; left: 0px; width: 720px; height: 404.484375px;"></iframe>
          </div>
        </div>
      </figure><h2 id="qu-esperar-de-este-tutorial">Qué Esperar de este Tutorial</h2><p>Aquí hay un ejemplo del chatbot Discord AI que habremos creado al final de este tutorial.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/08/discord.gif" class="kg-image" alt="discord" width="600" height="400" loading="lazy"><figcaption>Demostración de chat con mi bot en Discord. Dibujé el ícono del bot ?</figcaption></figure><p>Mi proyecto de chatbot comenzó como una broma con un amigo cuando jugábamos videojuegos.</p><p>Honestamente, estoy sorprendido por lo popular que se volvió - hubo 5900 vistas de mi tutorial anterior, además, cuando implementé mi bot en un servidor de más de 1000 usuarios, la gente lo inundó con más de 300 mensajes en una hora, colapsando efectivamente el bot. ? </p><p>Dado que mucha gente está interesada en construir sus propios bots basados en sus personajes favoritos, actualicé mi tutorial para incluir una explicación detallada sobre cómo recopilar datos de texto para cualquier personaje, ficticio o no ficticio.</p><p>¡También puedes crear un conjunto de datos personalizado que capture el discurso entre usted y sus amigos y crear un chatbot que hable como usted!</p><p>Otras actualizaciones en este tutorial abordan los cambios en los servicios de alojamiento de modelos de Hugging Face, incluidos los cambios de API que afectan la forma en que empujamos el modelo a los repositorios de modelos de Hugging Face.</p><h2 id="esquema-de-este-tutorial"><strong>Esquema de este Tutorial</strong></h2><p>La versión de video de este tutorial tiene una duración total de una hora y presenta los siguientes temas:</p><ol><li>Reúne datos de texto para su personaje utilizando uno de estos dos métodos: busque conjuntos de datos prefabricados en <strong>Kaggle</strong> o cree conjuntos de datos personalizados a partir de transcripciones sin procesar.</li><li>Entrena el modelo en <strong>Google Colab</strong>, un entorno de Jupyter Notebook basado en la nube con GPU gratuitas.</li><li>Implementa el modelo en <strong>Hugging Face</strong>, un servicio de hospedaje de modelos de AI.</li><li>Crea un bot de Discord en <strong>Python</strong> o <strong>JavaScript</strong>, ¡usted elige! ?</li><li>Configure los permisos del bot de Discord para que no envíe spam a los canales que no son bots</li><li>Aloja el bot en <strong><strong>Repl.it.</strong></strong></li><li>Mantenga el bot funcionando indefinidamente con <strong><strong>Uptime Robot.</strong></strong></li></ol><p>Para saber más sobre cómo crear bots de Discord, también te pueden resultar útiles este post de freeCodeCamp: hay una versión en <a href="https://www.freecodecamp.org/espanol/news/crea-un-bot-de-discord-con-javascript-nodejs/">JavaScript</a>.</p><h2 id="c-mo-preparar-los-datos"><strong>Cómo Preparar los Datos</strong></h2><p>Para que nuestro chatbot aprenda a conversar, necesitamos datos de texto en forma de diálogos. Así es esencialmente cómo nuestro chatbot responderá a diferentes intercambios y contextos.</p><h3 id="-est-tu-personaje-favorito-en-kaggle"><strong>¿Está tu personaje favorito en Kaggle?</strong></h3><p>Hay muchos conjuntos de datos interesantes en Kaggle para dibujos animados populares, programas de televisión y otros medios. Por ejemplo:</p><ul><li><a href="https://www.kaggle.com/andradaolteanu/rickmorty-scripts">Rick and Morty</a></li><li><a href="https://www.kaggle.com/gulsahdemiryurek/harry-potter-dataset?select=Harry+Potter+1.csv">Harry Potter</a></li><li><a href="https://www.kaggle.com/mitramir5/the-big-bang-theory-series-transcript">The Big Bang Theory</a></li><li><a href="https://www.kaggle.com/anderfj/game-of-thrones-series-scripts-breakdowns">Game of Thrones</a></li></ul><p>Solo necesitamos dos columnas de estos conjuntos de datos: <strong>nombre del personaje</strong> y <strong>línea de diálogo</strong>.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screen-Shot-2021-08-25-at-14.07.59.png" class="kg-image" alt="Screen-Shot-2021-08-25-at-14.07.59" width="600" height="400" loading="lazy"><figcaption>Ejemplo de conjunto de datos: transcripción de la película de Harry Potter</figcaption></figure><h3 id="-no-puedes-encontrar-tu-personaje-favorito-en-kaggle"><strong>¿No puedes encontrar tu personaje favorito en Kaggle?</strong></h3><p>¿No puedes encontrar tu personaje favorito en Kaggle? No hay problema. Podemos crear conjuntos de datos a partir de transcripciones sin procesar. Un buen lugar para buscar transcripciones es <a href="https://www.fandom.com/explore">Transcript Wiki</a>. Por ejemplo, mira esta transcripción de <a href="https://www.fandom.com/articles/captain-america-civil-war-roundtable-discussion">'Captain America: Civil War' Roundtable.</a></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/05/Screenshot-2023-05-05-at-11.58.04-AM.png" class="kg-image" alt="Screen-Shot-2021-08-25-at-14.13.57" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/05/Screenshot-2023-05-05-at-11.58.04-AM.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2023/05/Screenshot-2023-05-05-at-11.58.04-AM.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2023/05/Screenshot-2023-05-05-at-11.58.04-AM.png 1075w" sizes="(min-width: 720px) 720px" width="1075" height="993" loading="lazy"><figcaption>Ejemplo: Transcripción de Peppa Pig</figcaption></figure><p>Usando una expresión regular como <code>([a-zA-Z|\s]+): (.+)</code>, podemos extraer las dos columnas de interés, el nombre del personaje y la línea de diálogo.</p><p><a href="https://pythex.org/?regex=(%5Ba-zA-Z%7C%5Cs%5D%2B)%3A%20(.%2B)&amp;test_string=Drew%20Dietsch%3A%20Welcome%20to%20the%20first%20Fandom%20chat%20roundtable!%20We%E2%80%99re%20kicking%20off%20this%20(hopefully)%20recurring%20feature%20discussing%20Captain%20America%3A%20Civil%20War.%20There%E2%80%99s%20plenty%20to%20get%20into%2C%20but%20I%20figure%20we%E2%80%99ll%20start%20off%20with%20a%20bang%3A%20is%20Tom%20Holland%20the%20best%20on-screen%20Peter%20Parker%2FSpider-Man%20we%E2%80%99ve%20gotten%20yet%3F%0A%0A%0ATroy%20Anderson%3A%20Of%20course%2C%20but%20let%E2%80%99s%20not%20overpraise%20until%20he%20gets%20a%20solo%20flick.%0A%0AEric%20Fuchs%3A%20Tom%20Holland%20looked%20creepily%20like%20Tobey%20Maguire%20to%20me.%20He%20had%20a%20really%20nerdy%20vibe%20to%20him.%20But%20of%20course%2C%20the%20real%20issue%20is%20that%20Marisa%20Tomei%20is%20the%20best%20Aunt%20May%20ever.%0A%0ATroy%3A%20Hottest%20May%20Parker.%0A%0ADanielle%20Ryan%3A%20Definitely%20hottest%20May.%20I%20thought%20Tom%20Holland%20looked%20like%20Anton%20Yelchin.%0A%0AEric%3A%20It%20wasn%E2%80%99t%20just%20the%20suit%20that%20fit%2C%20I%20thought%20his%20fighting%20quips%20were%20the%20most%20Spider-Man-y%20that%20he%E2%80%99s%20ever%20been%20on%20screen.&amp;ignorecase=0&amp;multiline=0&amp;dotall=0&amp;verbose=0">¡Pruébelo tu mismo en este sitio web de expresiones regulares de Python!</a></p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/05/Screenshot-2023-05-05-at-1.48.46-PM.png" class="kg-image" alt="Screen-Shot-2021-08-25-at-14.58.35" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/05/Screenshot-2023-05-05-at-1.48.46-PM.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2023/05/Screenshot-2023-05-05-at-1.48.46-PM.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2023/05/Screenshot-2023-05-05-at-1.48.46-PM.png 1118w" sizes="(min-width: 720px) 720px" width="1118" height="1082" loading="lazy"></figure><h2 id="c-mo-entrenar-el-modelo"><strong>Cómo entrenar el modelo</strong></h2><p>Debajo del capó, nuestro modelo será un <strong>transformador generativo preentrenado (Generative Pre-trained Transfomer - GPT)</strong>, el modelo de lenguaje más popular en estos días.</p><p>En lugar de entrenar desde cero, cargaremos el GPT previamente entrenado de Microsoft, <code>DialoGPT-small</code>, y lo ajustaremos utilizando nuestro conjunto de datos.</p><p>Mi repositorio de GitHub para este tutorial contiene el <a href="https://github.com/RuolinZheng08/twewy-discord-chatbot/blob/main/model_train_upload_workflow.ipynb">archivo de notebook </a>llamado <code>model_train_upload_workflow.ipynb</code> para que puedas comenzar. Todo lo que necesitas hacer es lo siguiente: </p><ol><li>Sube el archivo a <a href="https://colab.research.google.com/">Google Colab</a></li><li>Seleccione <strong>GPU</strong> como tiempo de ejecución, lo que acelerará el entrenamiento de nuestro modelo.</li><li>Cambie el conjunto de datos y el carácter de destino en fragmentos de código como:</li></ol><pre><code class="language-python">data = pd.read_csv('MI-CONJUNTO-DE-DATOS.csv')
NOMBRE_DEL_PERSONAJE = 'MI-PERSONAJE'</code></pre><p>Revisar la sección de entrenamiento del cuaderno debería tomar menos de media hora. Tengo alrededor de 700 líneas y el entrenamiento toma menos de diez minutos. El modelo se almacenará en una carpeta llamada <code>output-small</code>.</p><p>¿Quieres un modelo aún más inteligente y elocuente? Siéntase libre de entrenar un modelo más grande como <code>DialoGPT-medium</code> o incluso <code>DialoGPT-large</code>. El tamaño del modelo aquí se refiere al número de parámetros en el modelo. Más parámetros permitirán que el modelo capte más complejidad del conjunto de datos.</p><p>También puedes aumentar la cantidad de épocas de entrenamiento buscando <code>num_train_epochs</code> en el cuaderno. Esta es la cantidad de veces que el modelo recorrerá el conjunto de datos de entrenamiento. El modelo generalmente se volverá más inteligente cuando tenga más exposición al conjunto de datos.</p><p>Sin embargo, tenga cuidado de no sobre ajustar el modelo: si el modelo se entrena para demasiadas épocas, puede memorizar el conjunto de datos y recitar renglones del conjunto de datos cuando tratamos de conversar con él. Esto no es ideal, ya que queremos que la conversación sea más orgánica.</p><h2 id="c-mo-alojar-el-modelo"><strong>Cómo alojar el modelo</strong></h2><p>Alojaremos el modelo en Hugging Face, que proporciona una API gratis para que podamos consultar el modelo.</p><p>Regístrese en <a href="https://huggingface.co">Hugging Face</a> y crea un nuevo repositorio de modelos haciendo clic en <strong>Nuevo modelo</strong>. Obtenga su token de API yendo a <strong>Editar perfil</strong> &gt; <strong>Tokens de API</strong>. Necesitaremos este token cuando construyamos el bot Discord.</p><p>Sigue junto con esta sección en mi video para cargar el modelo. Además, recuerda etiquetarlo como <strong>conversacional</strong> en su Tarjeta Modelo (equivalente a su <code>README.md</code>):</p><pre><code>---
tags:
- conversational // conversacional
---

# Mi Modelo Impresionante

</code></pre><p>Sabrá que todo funciona bien si puede conversar con la modelo en el navegador.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/huggingface3.gif" class="kg-image" alt="huggingface3" width="600" height="400" loading="lazy"></figure><h2 id="c-mo-construir-el-bot-de-discord"><strong>Cómo Construir el Bot de Discord</strong></h2><p>Vaya a la página del <a href="https://discord.com/developers/applications">desarrollador de Discord</a>, cree una aplicación y añádale un bot. Dado que nuestro chatbot solo responderá a los mensajes de los usuarios, basta con marcar <strong>Permisos de Texto &gt; Enviar Mensajes </strong>en la Configuración de permisos del bot. Copie el token de API del bot para usarlo más tarde.</p><p>Regístrese en <a href="https://repl.it/">Repl.it</a> y crea un nuevo Repl, <strong>Python</strong> o <strong>Node.js</strong> para JavaScript, con el que estés trabajando. </p><p>Almacenemos nuestros tokens API para <strong><strong>Hugging Face</strong></strong> y <strong><strong>Discord</strong></strong> como variables de entorno, llamados <code>HUGGINGFACE_TOKEN</code> y <code>DISCORD_TOKEN</code> respectivamente. Esto ayuda a mantenerlos en secreto.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/repl.png" class="kg-image" alt="repl" width="600" height="400" loading="lazy"></figure><p>Copie mi <a href="https://github.com/RuolinZheng08/twewy-discord-chatbot/blob/main/discord_bot.py">secuencia de comandos de Python</a> para un bot de Python y mi <a href="https://github.com/RuolinZheng08/twewy-discord-chatbot/blob/main/discord_bot.js">secuencia de comandos de JS</a> para un bot de JS. Tenga en cuenta que para el bot JS, debido a una incompatibilidad de versión con Node y NPM de Repl.it, necesitaremos especificar explícitamente una versión inferior del API de Discord en <code>package.json</code>.</p><pre><code>"dependencies": {
    "discord.js": "^12.5.3",
}</code></pre><p>¡Con eso, nuestro bot está listo para funcionar! Inicie la secuencia de comandos Repl presionando <strong>Run</strong>, agregue el bot a un servidor, escribe algo en el canal y disfrute de la respuesta ingeniosa del bot.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/discord-1.gif" class="kg-image" alt="discord-1" width="600" height="400" loading="lazy"></figure><h2 id="c-mo-mantener-el-bot-en-l-nea"><strong>Cómo Mantener el Bot en Línea</strong></h2><p>Un problema con nuestro bot es que se detiene tan pronto como <strong>detenemos</strong> la ejecución de Repl (equivalentemente, si cerramos la ventana del navegador Repl.it).</p><p>Para evitar esto y mantener nuestro bot funcionando indefinidamente, configuraremos un servidor web para que contenga el script del bot y usaremos un servicio como <a href="https://uptimerobot.com/">Uptime Robot</a> para fijar nuestro servidor cada cinco minutos para que nuestro servidor permanezca vivo.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screen-Shot-2021-08-25-at-15.29.06.png" class="kg-image" alt="Screen-Shot-2021-08-25-at-15.29.06" width="600" height="400" loading="lazy"></figure><p>En mi videotutorial, copié el código del servidor de esta publicación de freeCodeCamp (<a href="https://www.freecodecamp.org/espanol/news/crea-un-bot-de-discord-con-javascript-nodejs/">versión de JavaScript</a>). Luego, configuré el monitor en Uptime Robot. Ahora mi bot continúa respondiendo a mis mensajes, incluso si cierro el navegador (o apago mi computadora por completo).</p><p>¡Felicitaciones por llegar al final de este tutorial! ¡Espero que hayas disfrutado creando el bot y divirtiéndote chateando con tu personaje favorito! ?</p><p>¿Interesado en el modelo que entrené? Échale un vistazo en Hugging Face:</p><figure class="kg-card kg-bookmark-card"><a class="kg-bookmark-container" href="https://huggingface.co/r3dhummingbird/DialoGPT-medium-joshua?text=Hey+my+name+is+Julien%21+How+are+you%3F"><div class="kg-bookmark-content"><div class="kg-bookmark-title">r3dhummingbird/DialoGPT-medium-joshua · Hugging Face</div><div class="kg-bookmark-description">We’re on a journey to advance and democratize artificial intelligence through open source and open science.</div><div class="kg-bookmark-metadata"></div></div><div class="kg-bookmark-thumbnail"><img src="https://raw.githubusercontent.com/RuolinZheng08/twewy-discord-chatbot/main/gif-demo/icon.png" width="810" height="810" alt="icon" loading="lazy"></div></a></figure><p>¡Gracias por leer!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Generador de números aleatorios: ¿Cómo generan las computadoras números aleatorios? ]]>
                </title>
                <description>
                    <![CDATA[ Las personas han estado usando números aleatorios durante milenios, por lo que el concepto no es nuevo. Desde la lotería en la antigua Babilonia hasta las mesas de ruleta en Monte Carlo y los juegos de dados en Las Vegas, el objetivo es dejar el resultado final al azar. Pero ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/generador-de-numeros-aleatorios-como-las-computadoras-generan-numeros-aleatorios/</link>
                <guid isPermaLink="false">644eb483e59d8f07c2db301c</guid>
                
                    <category>
                        <![CDATA[ Matemáticas ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vanessa Pineiro Morales ]]>
                </dc:creator>
                <pubDate>Fri, 05 May 2023 01:36:30 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/04/5f9c9819740569d1a4ca1826.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/random-number-generator/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Random Number Generator: How Do Computers Generate Random Numbers?</a>
      </p><p>Las personas han estado usando <strong>números aleatorios</strong> durante milenios, por lo que el concepto no es nuevo. Desde la lotería en la antigua Babilonia hasta las mesas de ruleta en Monte Carlo y los juegos de dados en Las Vegas, el objetivo es dejar el resultado final al azar.</p><p>Pero dejando de lado las apuestas, la <strong>aleatoriedad</strong> tiene muchos usos en la ciencia, las estadísticas, la criptografía y más. Sin embargo, el uso de dados, monedas o medios similares como dispositivo aleatorio tiene sus limitaciones.</p><p>Debido a la naturaleza mecánica de estas técnicas, la generación de grandes cantidades de números aleatorios requiere una gran cantidad de tiempo y trabajo. Gracias al ingenio humano tenemos a nuestra disposición herramientas y métodos más poderosos.</p><h2 id="m-todos-para-generar-n-meros-aleatorios">Métodos para generar números aleatorios</h2><h3 id="n-meros-aleatorios-verdaderos">Números Aleatorios Verdaderos</h3><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/06/image-145-opt.png" class="kg-image" alt="image-145-opt" width="600" height="400" loading="lazy"><figcaption>Imagen de un dispositivo de procesamiento de salida digital de entrada analógica. Foto por <a href="https://unsplash.com/@harrisonbroadbent?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Harrison Broadbent</a></figcaption></figure><p>Consideremos dos métodos principales utilizados para generar números aleatorios. El <strong>primer método</strong> se basa en un proceso físico y extrae la fuente de aleatoriedad de algún fenómeno físico que <strong>se</strong> <strong>espera que sea aleatorio</strong>.</p><p>Tal fenómeno ocurre fuera de la computadora. Se mide y ajusta por posibles sesgos debidos al proceso de medición. Los ejemplos incluyen la descomposición radiactiva, el efecto fotoeléctrico, la radiación de fondo cósmica, el ruido atmosférico (que usaremos en este artículo) y más.</p><p>Por tanto, los números aleatorios generados basándose en dicha aleatoriedad se denominan números aleatorios "<strong>verdaderos</strong>".</p><p>Consideremos dos métodos principales utilizados para generar números aleatorios. El primer método se basa en un proceso físico y extrae la fuente de aleatoriedad de algún fenómeno físico que se espera que sea aleatorio.</p><p>Tal fenómeno ocurre fuera de la computadora. Se mide y ajusta por posibles sesgos debidos al proceso de medición. Los ejemplos incluyen la desintegración radiactiva, el efecto fotoeléctrico, la radiación de fondo cósmica, el ruido atmosférico (que usaremos en este artículo) y más.</p><p>Por tanto, los números aleatorios generados basándose en dicha aleatoriedad se denominan números aleatorios "verdaderos".</p><p>Técnicamente, la parte del hardware consiste de un dispositivo que convierte la energía de una forma a otra (por ejemplo, radiación en una señal eléctrica), un amplificador y un convertidor de analógico a digital para convertir la salida en un número digital.</p><h2 id="-qu-son-los-n-meros-pseudoaleatorios">¿Qué son los números pseudoaleatorios?</h2><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/06/image-146-opt.png" class="kg-image" alt="image-146-opt" width="600" height="400" loading="lazy"><figcaption>Imagen del código de computadora que fluye a través de la pantalla de la computadora. Foto por <a href="https://unsplash.com/@markusspiske?utm_source=ghost&amp;utm_medium=referral&amp;utm_campaign=api-credit">Markus Spiske</a>.</figcaption></figure><p>Como alternativa a los números aleatorios "verdaderos", el <strong>segundo método</strong> para generar números aleatorios involucra algoritmos computacionales que pueden producir resultados aparentemente aleatorios.</p><p>¿Por qué aparentemente aleatorio? Porque los resultados finales obtenidos están, de hecho, completamente determinados por un valor inicial, también conocido como valor <strong>semilla</strong> o <strong>clave</strong>. Por lo tanto, si sabes el valor de la clave y cómo funciona el algoritmo, podría reproducir estos resultados aparentemente aleatorios.</p><p>Los generadores de números aleatorios de este tipo se denominan frecuentemente generadores de <strong>números pseudoaleatorios</strong> y, como resultado, generan números pseudoaleatorios.</p><p>Aunque este tipo de generador normalmente no recopila datos de fuentes de aleatoriedad natural, dicha recopilación de claves puede hacerse posible cuando sea necesario.</p><p>Comparemos algunos aspectos de los generadores de números aleatorios verdaderos o <strong>TRNG</strong> y los generadores de números pseudoaleatorios o <strong>PRNG</strong>.</p><p>Los PRNG son más rápidos que los TRNG. Debido a su naturaleza determinista, son útiles cuando necesita reproducir una secuencia de eventos aleatorios. Esto ayuda mucho en las pruebas de código, por ejemplo.</p><p>Por otro lado, los TRNG no son periódicos y funcionan mejor en funciones sensibles a la seguridad, como el cifrado.</p><p>Un <strong>período</strong> es el número de iteraciones por las que pasa un PRNG antes de que comience a repetirse. Por lo tanto, en igualdad de condiciones, un PRNG con un período más largo requeriría más recursos de la computadora para predecir y descifrar.</p><h2 id="ejemplo-de-algoritmo-para-el-generador-de-n-meros-pseudoaleatorios">Ejemplo de algoritmo para el generador de números pseudoaleatorios</h2><p>Una computadora ejecuta código que se basa en un conjunto de reglas a seguir. Para los PRNG en general, esas reglas giran en torno a lo siguiente:</p><ol><li><strong>Acepta</strong> algún número de entrada inicial, que es una semilla o clave.</li><li><strong>Aplica</strong> esa semilla en una secuencia de operaciones matemáticas para generar el resultado. Ese resultado es el número aleatorio.</li><li><strong>Usa</strong> ese número aleatorio resultante como semilla para la siguiente iteración.</li><li><strong>Repite</strong> el proceso para emular la aleatoriedad.</li></ol><p>Ahora vamos a ver un ejemplo.</p><h3 id="el-generador-congruencial-lineal">El generador congruencial lineal</h3><p>Este generador produce una serie de números pseudoaleatorios. Con una semilla inicial <strong><strong>X<sub>0</sub></strong> </strong>y parámetros enteros <strong>a</strong> como multiplicador, <strong>b</strong> como incremento y <strong>m</strong> como módulo, el generador se define por la relación lineal: <strong><strong>X<sub>n</sub> ≡ (aX<sub>n-1</sub> + b)mod m</strong></strong>. O usando una sintaxis más amigable con la programación: <strong><strong>X<sub>n</sub> = (a * X<sub>n-1</sub> + b) % m</strong></strong>.</p><p>Cada uno de estos miembros debe satisfacer las siguientes condiciones:</p><ul><li><strong><strong>m &gt; </strong>0<strong> </strong></strong>(el módulo es positivo),</li><li><strong><strong>0 &lt; a &lt; m </strong></strong>(el multiplicador es positivo pero menor que el módulo),</li><li><strong><strong>0 </strong></strong>≤<strong><strong> b &lt; m</strong></strong> (el incremento no es negativo, pero es menor que el módulo), y</li><li><strong><strong>0 </strong></strong>≤<strong><strong> X</strong></strong><sub><strong><strong>0</strong></strong></sub><strong><strong> &lt; m </strong></strong>(la semilla no es negativa, pero es menor que el módulo).</li></ul><p>Vamos a crear una función de JavaScript que tome los valores iniciales como argumentos y devuelva un arreglo de números aleatorios de una longitud dada:</p><pre><code>
    // x0=semilla; a=multiplicador; b=incremento; m=módulo; n=longitud deseada de el arreglo;
	const generadorAleatorioLineal = (x0, a, b, m, n) =&gt; {
        const resultados = []
        for (let i = 0; i &lt; n; i++) {
        	x0 = (a * x0 + b) % m
            resultados.push(x0)
        }
        return resultados
    }
	</code></pre><p>El generador congruencial lineal es uno de los algoritmos PRNG más antiguos y conocidos.</p><p>En cuanto a los algoritmos generadores de números aleatorios que son ejecutables por computadoras, datan de las décadas de 1940 y 1950 (el método del cuadrado medio y el generador Lehmer, por ejemplo) y continúan escribiéndose hoy (Xoroshiro128+, Squares RNG y más).</p><h2 id="ejemplo-de-un-generador-de-n-meros-aleatorios">Ejemplo de un generador de números aleatorios</h2><p>Cuando decidí escribir este artículo sobre la incorporación de un generador de números aleatorios en una página web, tenía que tomar una decisión.</p><p>Podría haber usado la función <strong><strong><code>Math.random()</code> </strong></strong>de JavaScript como base y generar resultados en números pseudoaleatorios como lo hice en artículos anteriores.</p><p>Pero este artículo en sí trata sobre la generación de números aleatorios. Así que decidí aprender a recopilar datos basados en la aleatoriedad "verdadera" y compartir mi descubrimiento con ustedes.</p><p>El código obtiene datos de una API, cortesía de Random.org. Este recurso en línea tiene una gran cantidad de herramientas útiles y personalizables y viene con una excelente documentación para acompañarlo.</p><p>La aleatoriedad proviene del ruido atmosférico. Pude usar funciones asincrónicas. Eso es un gran beneficio en el futuro. La función central se ve así:</p><pre><code>// Genera un número aleatorio dentro del intervalo indicado por el usuario
const obtenerAleatorio = async (min, max, base) =&gt; {
   		const respuesta = await 	fetch("https://www.random.org/integers/?num=1&amp;min="+min+"
    &amp;max="+max+"&amp;col=1&amp;base="+base+"&amp;format=plain&amp;rnd=new")
          	return respuesta.text() 
   	} </code></pre><p>Los parámetros que toma permiten al usuario personalizar la salida de números aleatorios. Por ejemplo, <strong>min</strong> y <strong>max</strong> le permiten establecer límites inferiores y superiores en la salida generada. Y la <strong>base</strong> determina si la salida se imprime como binario, decimal o hexadecimal.</p><p>Nuevamente, elegí esta configuración, pero hay muchas más disponibles en la fuente.</p><p>Al hacer clic en el botón Generar, se llama a la función <code>manejarGenerar()</code>. A la vez, invoca la función asíncrona <code>obtenerAleatorio()</code>, gestiona el manejo de errores y genera resultados:</p><pre><code>
    // Gestión de salida
    const manejarGenerar = () =&gt; {
    	handleActive(generateButton)
        const base = binary.checked ? 2 : decimal.checked ? 10 : 16
        if (!minimum.value || !maximum.value) {
            prompter.style.color = 'red' 
        	prompter.textContent = "Ingrese valores mínimos y máximos"
        } else {
        	obtenerAleatorio(minimum.value, maximum.value, base).then((data) =&gt; {
        		resultValue.textContent = data
        		prompter.textContent = ""    
        	}).catch((error) =&gt; {
        		resultValue.textContent = 'ERROR'
        		prompter.textContent = 'Error de conexión. Incapaz de generar';    
        	})
       		 handleRestart()
        }
        
   }
    </code></pre><p>El resto del código se ocupa de la estructura, la apariencia y el estilo de HTML.</p><p>El código está listo para ser incrustado y utilizado dentro de esta página web. Lo separé en partes y lo proporcioné con comentarios detallados. Se puede modificar fácilmente. También puede modificar la funcionalidad y los estilos según lo requieran sus necesidades.</p><p>Este es el enlace al repositorio de GitHub del código completo: <a href="https://github.com/sandroarobeli/random-generator">https://github.com/sandroarobeli/random-generator</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Libros que Debes Leer para Aprender a Programar en Java ]]>
                </title>
                <description>
                    <![CDATA[ Hola a todos, hoy en día es el mundo de los cursos en línea. Todo el mundo habla de aprender en línea, Youtube, cursos gratuitos en Coursera y otros sitios web, lo cual es excelente, como cursos en línea pueden ayudar a aprender más rápido, pero creo que los libros ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/libros-que-debes-leer-para-aprender-a-programar-en-java/</link>
                <guid isPermaLink="false">63cb0114700708073437bdac</guid>
                
                    <category>
                        <![CDATA[ java ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vanessa Pineiro Morales ]]>
                </dc:creator>
                <pubDate>Tue, 24 Jan 2023 19:25:37 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/01/Screen-Shot-2023-01-20-at-4.04.45-PM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/must-read-books-to-learn-java-programming-327a3768ea2f/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Must-read books to learn Java programming</a>
      </p><p>Hola a todos, hoy en día es el mundo de los cursos en línea. Todo el mundo habla de aprender en línea, Youtube, cursos gratuitos en Coursera y otros sitios web, lo cual es excelente, como cursos en línea pueden ayudar a aprender más rápido, pero creo que los libros aún deben ser una parte importante de su aprendizaje, ya que brindan el conocimiento más profundo y, a menudo, escrito por la autoridad en el tema.</p><p>Si estás aprendiendo programación Java, prepárese para conocer algunos de los libros más increíbles para aprender y dominar la programación Java en este artículo.</p><p>Cada vez que un programador comienza a aprender el lenguaje de programación Java, la primera pregunta que hacen es: "¿Qué libro debo consultar para aprender Java?" o “¿Cuál es el mejor libro para aprender Java para principiantes?” o “¿Puedes decirme algunos buenos libros para aprender Java?” Eso, en sí mismo, dice lo importante que son los libros de Java para los programadores, especialmente los principiantes.</p><p>A pesar de tener tantos recursos gratuitos disponibles en Java, como tutoriales, cursos en línea, consejos, blogs y ejemplos de código, los libros de Java tienen su propio lugar porque:</p><ul><li>Están escritos por programadores que son una autoridad en el tema.</li><li>Cubren el tema con más detalles y explicaciones.</li></ul><p>Estos libros de Java son mis favoritos personales, y cada vez que tengo tiempo, prefiero leerlos para refrescar mis conocimientos. Aunque ya he leído muchos de ellos (he leído <a href="https://www.amazon.com/Effective-Java-3rd-Joshua-Bloch/dp/0134685997/?tag=javamysqlanta-20" rel="noopener"><strong><strong>Effective Java</strong></strong></a> al menos cuatro veces hasta ahora), siempre quiero aprender algo nuevo y mi búsqueda de grandes libros nunca termina.</p><p>Estos libros son algunos de los mejores disponibles en la actualidad y son igualmente útiles para programadores de Java principiantes, intermedios y avanzados.</p><p>No importa si eres completamente nuevo en Java o si ha estado programando en Java durante algún tiempo, aprenderás muchas cosas nuevas a través de estos libros.</p><p>Habiendo dicho eso, no todos los libros son igualmente adecuados para todos los programadores. Para los principiantes, <a href="https://www.amazon.com/dp/0596009208/?tag=javamysqlanta-20"><em>Head First Java</em></a> sigue siendo el mejor libro para empezar, y para el desarrollador avanzado de Java, <a href="https://www.amazon.com/Effective-Java-3rd-Joshua-Bloch/dp/0134685997/?tag=javamysqlanta-20" rel="noopener"><em><em>Effective Java</em></em></a> es un buen libro para empezar.</p><h3 id="los-10-mejores-libros-para-aprender-a-programar-en-java">Los 10 Mejores Libros para Aprender a Programar en Java</h3><p>Aquí está mi colección de libros de Java que sugiero a todos los programadores que quieran aprender Java. Contiene libros para programadores principiantes y experimentados.</p><p>Estos libros cubren una variedad de áreas, incluidos los fundamentos básicos de Java, el framework de colección de Java, subprocesos múltiples y concurrencia, ajustes internos y de rendimiento de JVM, patrones de diseño, etc.</p><h4 id="1-head-first-java"><strong>1. Head First Java</strong></h4><p>Mucha gente pensará que este es un libro anticuado, pero para ser honesto, Head First Java es el mejor libro para cualquier programador que sea nuevo tanto en programación como en Java. La manera de explicar de cabeza es fenomenal y realmente disfruté su libro.</p><p>Head First Java cubre el conocimiento esencial de programación Java sobre características de clase, objeto, subproceso, colección y lenguaje, como genéricos, enumeraciones, argumentos variables o auto-boxing.</p><p>También tienen una sección avanzada sobre Swing, redes y Java IO, lo que los convierte en un paquete completo para principiantes de Java. Este debería ser el primer libro de Java que veas si estás empezando desde cero.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/01/51aHYpRqWvL._AC_SY1000_.jpeg" class="kg-image" alt="51aHYpRqWvL._AC_SY1000_" width="432" height="500" loading="lazy"></figure><p>Descargo de responsabilidad: recibiré una compensación si utilizas cualquier enlace de los libros enumerados aquí desde Amazon.</p><h4 id="2-head-first-design-patterns"><strong>2. Head First Design Patterns</strong></h4><p>El <a href="http://www.amazon.com/dp/0596007124/?tag=javamysqlanta-20" rel="noopener">Head First Design Pattern</a> es otro libro de Java de primera clase del laboratorio de Head-First.</p><p>Cuando comencé a leer este libro en 2006, no pensé mucho en los patrones de diseño, cómo resuelven problemas comunes, cómo aplicar un patrón de diseño, qué beneficios brindan y todo tipo de cosas básicas. Pero después de leer este libro de Java, me he beneficiado inmensamente.</p><p>El primer capítulo sobre herencia y composición, que es simplemente fantástico y promueve prácticas mejoradas al presentar un problema y luego la solución.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/01/61APhXCksuL._AC_SY1000_.jpeg" class="kg-image" alt="61APhXCksuL._AC_SY1000_" width="432" height="500" loading="lazy"></figure><p>Este libro también contiene viñetas útiles, ejercicios y mapas de memoria, que lo ayudan a comprender los patrones de diseño rápidamente.</p><p>Si desea aprender los patrones de diseño básicos de Java y los principios de diseño orientado a objetos, este es el primer libro de Java que debe consultar.</p><p>Una buena noticia sobre este libro es que la nueva edición se actualizó para Java SE 8, que le enseñará cómo desarrollar un patrón de diseño GOF clásico utilizando características de Java 8, como expresiones lambda y secuencias.</p><h4 id="3-effective-java"><strong>3. Effective Java</strong></h4><p><a href="http://www.amazon.com/dp/0321356683/?tag=javamysqlanta-20" rel="noopener">Effective Java</a> es uno de los mejores libros de Java en mi historial y uno de los más agradables. Tengo un gran respeto por Joshua Bloch, el autor, por su contribución al framework de la colección Java y al paquete Java Concurrency.</p><p>Effective Java es mejor para un programador experimentado que esté bien versado en la programación de Java. Es excelente para los programadores que desean compartir sus habilidades siguiendo las mejores prácticas de programación y que están ansiosos por escuchar a alguien que contribuyó al kit de desarrollo de Java (JDK).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/01/51N7QPvhS9L._AC_SY1000_.jpeg" class="kg-image" alt="51N7QPvhS9L._AC_SY1000_" width="497" height="648" loading="lazy"></figure><p>Effective Java consiste de una colección de las mejores prácticas de programación de Java, que van desde fábricas estáticas, serialización, igualdad y código hash hasta genéricos, enumeraciones, varargs y reflexión.</p><p>Este libro de programación Java cubre casi todos los aspectos de Java de una manera ligeramente diferente a la que está acostumbrado.</p><p>El año pasado se lanzó una nueva edición que introdujo funciones en JDK 7, 8 y 9, que se lanzó el año pasado en septiembre. También tiene un capítulo completo sobre lambdas.</p><h4 id="4-java-concurrency-in-practice"><strong>4. Java Concurrency in Practice</strong></h4><p><a href="https://www.amazon.com/dp/0321349601/?tag=javamysqlanta-20">Java Concurrency</a> in Practice es otro clásico de Joshua Bloch, Doug Lea y su equipo. Este es el mejor libro de Java sobre simultaneidad y subprocesos múltiples: una de las lecturas obligadas para los desarrolladores principales de Java.</p><p>Los puntos fuertes de la práctica de concurrencia en Java incluyen:</p><p>1) Este libro es muy detallado y captura detalles menores de subprocesos múltiples y concurrencia.</p><p>2) En lugar de centrarse en las clases básicas de Java, este libro se centra en las cuestiones y los problemas de concurrencia, como interbloqueo, inanición, seguridad de subprocesos, condiciones de carrera, y presenta formas de resolverlos utilizando clases de concurrencia de Java.</p><p>Este libro es un recurso excelente para aprender y dominar los paquetes y clases de concurrencia de Java, como CountDownLatch, CyclicBarrier, BlockingQueue o Semaphore. Esta es la principal razón por la que me gusta leer este libro de Java y leerlo una y otra vez.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/01/51v9-FC4MDL.jpeg" class="kg-image" alt="51v9-FC4MDL" width="378" height="500" loading="lazy"></figure><p>3) Otro punto fuerte de la práctica de concurrencia en Java son los ejemplos sensatos; los ejemplos de este libro son claros, concisos e inteligentes.</p><p>4) Este libro también es bueno para explicar lo que está mal y por qué está mal y cómo corregirlo, lo cual es esencial para que cualquier libro de Java tenga éxito.</p><p>En resumen, este es uno de los mejores libros para aprender concurrencia y subprocesos múltiples en Java. El contenido definitivamente es avanzado desde la perspectiva de un principiante, pero seguramente, este es un libro de lectura obligada para los programadores Java experimentados.</p><h4 id="5-java-generics-and-collections"><strong>5. Java Generics and Collections</strong></h4><p>The Java Generics and Collection de Naftalin y Philip Wadler de O'Reilly es otro buen libro sobre Java, que inicialmente olvidé incluir en mi lista pero lo incluyo ahora a pedido de muchos lectores.</p><p>Me gusta este libro por su contenido sobre genéricos y colecciones, que son áreas centrales del lenguaje Java.</p><p>Se espera que un programador experimentado tenga un conocimiento sólido de las colecciones y los genéricos de Java, y estos libros ayudan en esa área.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/01/41fJocDi3LL._AC_SY780_.jpeg" class="kg-image" alt="41fJocDi3LL._AC_SY780_" width="372" height="500" loading="lazy"></figure><p>Explica cada interfaz de colección, como Conjunto, Lista, Mapa, Cola, y su implementación, comparando qué tan bien funcionan en una situación diferente.</p><p>Realmente me encantó su tabla de comparación al final de cada capítulo, que le brinda una buena idea sobre cuándo usar una clase de colección de Java en particular, como <code>ArrayList</code>, <code>HashMap</code> o <code>LinkedHashMap</code>.</p><h4 id="6-java-performance-from-binu-john"><strong>6. Java Performance From Binu John</strong></h4><p>Este es otro buen libro que enseña sobre los aspectos internos de JVM, la recolección de basura, el ajuste de JVM y la creación de perfiles. etc., y recomiendo encarecidamente a todos los desarrolladores senior de Java que lean este libro. Este es también uno de mis favoritos personales.</p><p>Como nos estamos moviendo gradualmente, comenzamos desde un nivel de principiantes hasta un nivel intermedio y ahora el nivel superior.</p><p><em>Java Performance</em> tiene que ver con la supervisión del rendimiento, la creación de perfiles y las herramientas utilizadas para la supervisión del rendimiento de Java.</p><p>Este no es un libro de programación habitual. En su lugar, proporciona detalles sobre la JVM, la recolección de basura, la supervisión del almacenamiento dinámico de Java y la aplicación de generación de perfiles.</p><p>Me encantó su capítulo sobre la descripción general de JVM, y es una lectura obligada para obtener más información sobre JVM en un lenguaje sencillo.</p><p>Tanto los principiantes como los programadores intermedios pueden beneficiarse de este libro, pero es bueno tener algo de experiencia en Java antes de leerlo. Hasta ahora, este es el mejor libro de Java sobre monitoreo del rendimiento.</p><p>Este es otro libro de Java que debe leer si se toma en serio el rendimiento.</p><p>Hay un par de libros nuevos disponibles en Java, que cubren JDK 1.7. Para conocer el último libro sobre el rendimiento de Java, como <strong>Java Performance, The Definitive Guide de Scott Oaks</strong>, que sin duda vale la pena consultar antes de comprar este libro.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/01/Java-Performance-Definitive-Guide.jpeg" class="kg-image" alt="Java-Performance-Definitive-Guide" width="244" height="320" loading="lazy"></figure><h4 id="7-java-puzzlers"><strong>7. Java Puzzlers</strong></h4><p>Java Puzzlers es otro libro que vale la pena leer de Joshua Bloch, esta vez con Neal Gafter. Este libro trata sobre casos extremos y trampas en el lenguaje de programación Java.</p><p>Java es más seguro que C++, y la JVM hace un buen trabajo para liberar al programador de la asignación y desasignación de memoria propensa a errores. Pero aún así, Java tiene casos de esquina que pueden sorprender incluso al programador Java experimentado.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/01/Unknown.jpeg" class="kg-image" alt="Unknown" width="198" height="254" loading="lazy"></figure><p>Este libro de Java presenta estos peligros de Java y los explica con más detalle. Este es un buen libro de Java si le encantan los acertijos; incluso puede incluir muchos de estos en las entrevistas básicas de Java para verificar su conocimiento de Java.</p><p>No lo califico tan alto como <em><em>Effective Java</em></em> y <em><em>Java Concurrency in Practice</em></em>, pero aún puede intentarlo, especialmente para verificar su conocimiento sobre Java y sus casos de esquina, lo que lo ayudará a responder algunas de las preguntas difíciles de Java de entrevistas.</p><p>Para entender la mayor parte de este libro de Java, intente resolver acertijos usted mismo y luego busque explicaciones para que su conocimiento sea más concreto.</p><h4 id="8-head-first-object-oriented-analysis-and-design"><strong>8. Head First Object-Oriented Analysis and Design</strong></h4><p>Otro buen libro sobre principios de diseño y programación Java de la serie Head-First. <em>Head First Object-Oriented Analysis and Design</em> se puede leer junto con <em>Head First Design Patterns</em>.</p><p>Este libro se enfoca en los principios del diseño orientado a objetos, como favorecer la composición sobre la herencia, la programación para el interfaz en lugar de la implementación, DRY, etc.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/01/51FNFnkTMKL.jpeg" class="kg-image" alt="51FNFnkTMKL" width="432" height="500" loading="lazy"></figure><p>Una parte de aprender Java es escribir un buen código y seguir las mejores prácticas, y este libro es excelente para educar a los programadores sobre ellas.</p><p>El conocimiento obtenido con este libro es aplicable a muchos lenguajes de programación orientados a objetos y, en general, mejorará su comprensión del código y los principios de diseño de programación orientada a objetos.</p><h4 id="9-thinking-in-java"><strong>9. Thinking in Java</strong></h4><p><em><em>Thinking in Java</em></em> está escrito por Bruce Eckel, quien también es el autor de Thinking in C++ y usa su estilo único para enseñar el concepto de Java.</p><p>Muchos estarían de acuerdo en que este es uno de los mejores libros de Java, con una fortaleza que apunta a ejemplos inteligentes. Este es uno de los libros completos en Java y también puede usarse como referencia.</p><p>Hay un capítulo sobre IO mapeada en memoria de Java de <em>Thinking in Java</em>, que es mi favorito.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/01/61-ZAFCWcLL._AC_SY1000_.jpeg" class="kg-image" alt="61-ZAFCWcLL._AC_SY1000_" width="378" height="500" loading="lazy"></figure><p>Si no le gusta el estilo de enseñanza Head-First, pero necesita un libro de Java para principiantes con un estilo de ejemplo simple, <em>Thinking in Java</em> es una buena opción.</p><p>Es detallado, maduro y se actualiza con frecuencia, pero, si necesita más opciones, también puede consultar estos libros básicos de Java para principiantes.</p><h4 id="10-java-se-8-for-the-really-impatient"><strong><strong><strong>10. Java SE 8 for the Really Impatient</strong></strong></strong></h4><p>Este es uno de los mejores libros para aprender Java 8. También es mi libro Java 8 de propósito general. Si tienes menos tiempo y quieres aprender todas las cosas importantes sobre Java 8, este es el libro que debes consultar.</p><p>No tengo que recordarte de la habilidad de escribir de Cay. S. Horstmann’s, uno de los mejores autores en Java y a la altura de Joshua Bloch. He encontrado que ambos son muy legibles.</p><p>No te aburrirás, lo que suelen hacer los programadores cuando leen libros técnicos. Explica sobre la expresión lambda, Streams, interfaz funcional, referencias de métodos, nueva API de fecha y hora de Java y varias otras pequeñas mejoras como unir cadenas, anotaciones repetibles, etc. En resumen, uno de los mejores libros para aprender Java sin duda.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/01/51zveYV7hGL._AC_SY780_.jpeg" class="kg-image" alt="51zveYV7hGL._AC_SY780_" width="380" height="500" loading="lazy"></figure><h3 id="terminando">Terminando</h3><p>Esta fue mi lista de <strong>los mejores libros de programación Java</strong>. He leído todos los libros, algunos de ellos todavía los estoy leyendo y un par de ellos, como <em><em>Effective Java</em></em> y la serie Head-First, los he leído un par de veces. Muchos programadores me preguntan con qué libros deberían comenzar y qué libro de Java deberían leer ahora. Espero que hayas encontrado buenos libros en esta colección. ¡Feliz lectura!</p><h3 id="notas-finales"><strong>Notas finales</strong></h3><p>Gracias por leer este artículo hasta ahora. Puede que estés pensando que hay tantas cosas que aprender, tantos cursos a los que unirte, pero no tienes que preocuparte.</p><p>Soy un fanático particular de los cursos de Udemy, ya que son muy asequibles y brindan muchos valores en una cantidad muy pequeña, pero eres libre de elegir el curso que deseas.</p><p>Al final del día, debe tener suficiente conocimiento y experiencia al usar los recursos mencionados aquí.</p><p>¡Buena suerte con tu viaje por Java! Ciertamente <strong>no va a ser fácil</strong>, pero siguiendo esta hoja de ruta y guía, está un paso más cerca de convertirse en el desarrollador de Java que siempre quiso ser.</p><p>Si te gusta este artículo, considera seguirme en medium (javinpaul). Si desea recibir notificaciones de cada publicación nueva, ¡no olvide seguir a <a href="https://twitter.com/javarevisited">javarevisited</a> en Twitter!<br><br>Una vez más, todo lo mejor para su viaje de desarrollo de Java y muchas gracias a todos los autores por escribir libros tan increíbles. Estos libros de programación de Java son algunos de los mejores libros para aprender Java; incluso diría que algunos de ellos son los mejores libros de Java jamás publicados.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Tutorial de una Aplicación React CRUD: Cómo crear una aplicación de administración de libros en React desde cero ]]>
                </title>
                <description>
                    <![CDATA[ En este artículo, construirá una aplicación de administración de libros en React desde cero. Al crear esta aplicación, aprenderá:  1. Cómo realizar operaciones CRUD  2. Cómo usar React Router para navegar entre rutas  3. Cómo usar React Context API para pasar datos a través de rutas  ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/react-crud-app-tutorial-como-construir-una-aplicacion-de-administracion-de-libros-en-react-desde-cero/</link>
                <guid isPermaLink="false">63caa2da700708073437b76c</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vanessa Pineiro Morales ]]>
                </dc:creator>
                <pubDate>Tue, 24 Jan 2023 18:59:06 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/01/book_management.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/react-crud-app-how-to-create-a-book-management-app-from-scratch/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">React CRUD App Tutorial – How to Build a Book Management App in React from Scratch</a>
      </p><p>En este artículo, construirá una aplicación de administración de libros en React desde cero.</p><p>Al crear esta aplicación, aprenderá:</p><ol><li>Cómo realizar operaciones CRUD</li><li>Cómo usar React Router para navegar entre rutas</li><li>Cómo usar React Context API para pasar datos a través de rutas</li><li>Cómo crear un hook personalizado en React</li><li>Cómo almacenar datos en el almacenamiento local para conservarlos incluso después de actualizar la página</li><li>Cómo administrar los datos almacenados en el almacenamiento local mediante un hook personalizado</li></ol><p>y mucho más.</p><p>Usaremos React Hooks para construir esta aplicación. </p><h2 id="configuraci-n-inicial"><strong>Configuración inicial</strong></h2><p>Crear un nuevo proyecto usando <code>create-react-app</code>:</p><pre><code class="language-js">npx create-react-app administracion-de-libros-app
</code></pre><p>Una vez que se crea el proyecto, elimine todos los archivos de la carpeta <code>src</code> y crea archivos <code>index.js</code> y <code>styles.scss</code> dentro de la carpeta <code>src</code>. También, crea carpetas de <code>componentes</code>, <code>contexto</code>, <code>hooks</code> y <code>enrutadores</code> dentro de la carpeta <code>src</code>.</p><p>Instala las dependencias necesarias:</p><pre><code class="language-js">yarn add bootstrap@4.6.0 lodash@4.17.21 react-bootstrap@1.5.2 node-sass@4.14.1 react-router-dom@5.2.0 uuid@8.3.2
</code></pre><p>Abra styles.scss y agregue los contenidos de <a href="https://github.com/myogeshchavan97/react-book-management-app/blob/master/src/styles.scss">aquí</a> adentro.</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 <code>Header.js</code> dentro de la carpeta de <code>componentes</code> con el siguiente contenido:</p><pre><code class="language-jsx">import React from 'react';
import { NavLink } from 'react-router-dom';

const Header = () =&gt; {
  return (
    &lt;header&gt;
      &lt;h1&gt;Aplicación de Administración de Libros&lt;/h1&gt;
      &lt;hr /&gt;
      &lt;div className="links"&gt;
        &lt;NavLink to="/" className="link" activeClassName="active" exact&gt;
          Lista de Libros
        &lt;/NavLink&gt;
        &lt;NavLink to="/add" className="link" activeClassName="active"&gt;
          Agrega Libro
        &lt;/NavLink&gt;
      &lt;/div&gt;
    &lt;/header&gt;
  );
};

export default Header;
</code></pre><p>Aquí, hemos agregado dos enlaces de navegación utilizando el componente <code>NavLink</code> de <code>react-router-dom</code>: uno para ver una lista de todos los libros y el otro para agregar un nuevo libro.</p><p>Usamos <code>NavLink</code> en lugar de la etiqueta de anclaje ( <code>&lt;a /&gt;</code>) para que la página no se actualice cuando un usuario haga clic en cualquiera de los enlaces.</p><p>Cree un nuevo archivo llamado <code>ListaDeLibros.js</code> dentro de la carpeta de <code>componentes</code> con el siguiente contenido:</p><pre><code class="language-js">import React from 'react';

const ListaDeLibros = () =&gt; {
  return &lt;h2&gt;Lista de Libros&lt;/h2&gt;;
};

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

const AgregaLibro = () =&gt; {
  const handleOnSubmit = (libro) =&gt; {
    console.log(libro);
  };

  return (
    &lt;React.Fragment&gt;
      &lt;FormularioDeLibro handleOnSubmit={handleOnSubmit} /&gt;
    &lt;/React.Fragment&gt;
  );
};

export default AgregaLibro;
</code></pre><p>En este archivo, estamos mostrando un componente <code>FormularioDeLibro</code> (que aún tenemos que crear).</p><p>Para el componente <code>FormularioDeLibro</code>, estamos pasando el método <code>handleOnSubmit</code> para que podamos realizar algún procesamiento más adelante una vez que enviemos el formulario.</p><p>Ahora, crea un nuevo archivo <code>FormularioDeLibro.js</code> dentro de la carpeta de <code>componentes</code> con el siguiente contenido:</p><pre><code class="language-jsx">import React, { useState } from 'react';
import { Form, Button } from 'react-bootstrap';
import { v4 as uuidv4 } from 'uuid';

const FormularioDeLibro = (props) =&gt; {
  const [libro, setLibro] = useState({
    nombrelibro: props.libro ? props.libro.nombrelibro : '',
    autor: props.libro ? props.libro.autor : '',
    cantidad: props.libro ? props.libro.cantidad : '',
    precio: props.libro ? props.libro.precio : '',
    fecha: props.libro ? props.libro.fecha : ''
  });

  const [errorMsg, setErrorMsg] = useState('');
  const { nombrelibro, autor, precio, cantidad } = libro;

  const handleOnSubmit = (event) =&gt; {
    event.preventDefault();
    const valores = [nombrelibro, autor, precio, cantidad];
    let errorMsg = '';

    const todosLosCamposLlenos = valores.every((campo) =&gt; {
      const valor = `${campo}`.trim();
      return valor !== '' &amp;&amp; valor !== '0';
    });

    if (todosLosCamposLlenos) {
      const libro = {
        id: uuidv4(),
        nombrelibro,
        autor,
        precio,
        cantidad,
        fecha: new Date()
      };
      props.handleOnSubmit(libro);
    } else {
      errorMsg = 'Por favor, rellene todos los campos.';
    }
    setErrorMsg(errorMsg);
  };

  const handleInputChange = (event) =&gt; {
    const { nombre, valor } = event.target;
    switch (nombre) {
      case 'cantidad':
        if (valor === '' || parseInt(valor) === +valor) {
          setLibro((prevState) =&gt; ({
            ...prevState,
            [nombre]: valor
          }));
        }
        break;
      case 'precio':
        if (valor === '' || valor.match(/^\d{1,}(\.\d{0,2})?$/)) {
          setLibro((prevState) =&gt; ({
            ...prevState,
            [nombre]: valor
          }));
        }
        break;
      default:
        setLibro((prevState) =&gt; ({
          ...prevState,
          [nombre]: valor
        }));
    }
  };

  return (
    &lt;div className="main-form"&gt;
      {errorMsg &amp;&amp; &lt;p className="errorMsg"&gt;{errorMsg}&lt;/p&gt;}
      &lt;Form onSubmit={handleOnSubmit}&gt;
        &lt;Form.Group controlId="nombre"&gt;
          &lt;Form.Label&gt;Nombre del Libro&lt;/Form.Label&gt;
          &lt;Form.Control
            className="input-control"
            type="text"
            name="nombrelibro"
            value={nombrelibro}
            placeholder="Ingrese el nombre del libro"
            onChange={handleInputChange}
          /&gt;
        &lt;/Form.Group&gt;
        &lt;Form.Group controlId="autor"&gt;
          &lt;Form.Label&gt;Autor del Libro&lt;/Form.Label&gt;
          &lt;Form.Control
            className="input-control"
            type="text"
            name="autor"
            value={autor}
            placeholder="Ingrese el nombre del autor"
            onChange={handleInputChange}
          /&gt;
        &lt;/Form.Group&gt;
        &lt;Form.Group controlId="cantidad"&gt;
          &lt;Form.Label&gt;Cantidad&lt;/Form.Label&gt;
          &lt;Form.Control
            className="input-control"
            type="number"
            name="cantidad"
            value={cantidad}
            placeholder="Ingrese la cantidad disponible"
            onChange={handleInputChange}
          /&gt;
        &lt;/Form.Group&gt;
        &lt;Form.Group controlId="precio"&gt;
          &lt;Form.Label&gt;Precio del Libro&lt;/Form.Label&gt;
          &lt;Form.Control
            className="input-control"
            type="text"
            name="precio"
            value={precio}
            placeholder="Ingrese el precio del libro"
            onChange={handleInputChange}
          /&gt;
        &lt;/Form.Group&gt;
        &lt;Button variant="primary" type="submit" className="submit-btn"&gt;
          Enviar
        &lt;/Button&gt;
      &lt;/Form&gt;
    &lt;/div&gt;
  );
};

export default FormularioDeLibro;
</code></pre><p>Vamos a entender lo que estamos haciendo aquí.</p><p>Inicialmente, hemos definido un estado como un objeto usando el useState hook para almacenar todos los detalles ingresados de esta manera:</p><pre><code class="language-js">const [libro, setLibro] = useState({
    nombrelibro: props.libro ? props.libro.nombrelibro : '',
    autor: props.libro ? props.libro.autor : '',
    cantidad: props.libro ? props.libro.cantidad : '',
    precio: props.libro ? props.libro.precio : '',
    fecha: props.libro ? props.libro.fecha : ''
  });
</code></pre><p>Como usaremos el mismo componente <code>FormularioDeLibro</code> para agregar y editar el libro, primero verificamos si el prop del <code>libro</code> pasa o no usando el operador ternario.</p><p>Si el prop pasa, lo estamos configurando en el valor pasado, de lo contrario, una cadena vacía <code>('')</code>.</p><blockquote>No se preocupe si parece complicado ahora. Lo comprenderá mejor una vez que construyamos algunas funciones iniciales.</blockquote><p>Luego agregamos un estado para mostrar un mensaje de error y usamos la sintaxis de desestructuración de ES6 para hacer referencia a cada una de las propiedades dentro del estado de esta manera:</p><pre><code class="language-js">const [errorMsg, setErrorMsg] = useState('');
const { nombrelibro, autor, precio, cantidad } = libro;</code></pre><p>Desde el componente <code>FormularioDeLibro</code>, estamos devolviendo un Formulario donde ingresamos el nombre del libro, el autor del libro, la cantidad y el precio. Estamos usando el framework <a href="https://react-bootstrap.github.io">react-bootstrap</a> para mostrar el formulario en un formato agradable.</p><p>Cada campo de entrada ha agregado un controlador <code>onChange</code> que llama al método <code>handleInputChange</code>.</p><p>Dentro del método <code>handleInputChange</code>, agregamos una declaración de cambio para cambiar el valor del estado según el campo de entrada que se cambia.</p><p>Cuando escribimos algo en el campo de entrada de <code>cantidad</code>, <code>event.target.nombre</code> será <code>cantidad</code>, por lo que el primer caso de switch coincidirá. Dentro de la declaración switch , estamos verificando si el valor ingresado es un número entero sin un punto decimal.</p><p>Si es así, solo actualizamos el estado como se muestra a continuación:</p><pre><code class="language-js">if (valor === '' || parseInt(valor) === +valor) {
  setLibro((prevState) =&gt; ({
    ...prevState,
    [nombre]: valor
  }));
}
</code></pre><p>Entonces, el usuario no puede ingresar ningún valor decimal para el campo de entrada de cantidad.</p><p>Para el caso del switch de <code>precio</code>, buscamos un número decimal con solo dos dígitos después del punto decimal. Así que hemos agregado una verificación de expresión regular que se ve así: <code>value.match(/^\d{1,}(.\d{0,2})?$/)</code>.</p><p>Si el valor del precio coincide solo con la expresión regular, entonces actualizamos el estado.</p><p>Nota: Para los casos de switch de <code>cantidad</code> y <code>precio</code>, también estamos buscando valores vacíos como este: <code>valor === ''</code>. Esto es para permitir que el usuario elimine por completo el valor ingresado si es necesario.</p><p>Sin esa verificación, el usuario no podrá eliminar el valor ingresado presionando <code>Ctrl + A + Delete</code>.</p><p>Para todos los demás campos de entrada, se ejecutará el caso de switch predeterminado que actualizará el estado según el valor ingresado por el usuario.</p><p>A continuación, una vez que enviemos el formulario, se llamará al método <code>handleOnSubmit</code>.</p><p>Dentro de este método, primero verificamos si el usuario ha ingresado todos los detalles usando el método de <code>every</code> arreglo:</p><pre><code class="language-js">const todosLosCamposLlenos = valores.every((campo) =&gt; {
  const valor = `${campo}`.trim();
  return valor !== '' &amp;&amp; valor !== '0';
});</code></pre><p>El método de <code>every</code> arreglo es uno de los métodos de arreglo más útiles en JavaScript.</p><p>Si se completan todos los valores, entonces estamos creando un objeto con todos los valores completos. También estamos llamando al método <code>handleOnSubmit</code> pasando libro como argumento, de lo contrario, estamos configurando un mensaje de error.</p><p>El método <code>handleOnSubmit</code> se pasa como prop del componente <code>AgregaLibro</code>.</p><pre><code class="language-js">if (todosLosCamposLlenos) {
  const libro = {
    id: uuidv4(),
    nombrelibro,
    autor,
    precio,
    cantidad,
    fecha: new Date()
  };
  props.handleOnSubmit(libro);
} else {
  errorMsg = 'Por favor, rellene todos los campos.';
}
</code></pre><p>Tenga en cuenta que para crear una ID única llamamos al método <code>uuidv4()</code> del paquete <a href="https://www.npmjs.com/package/uuid">uuid</a> npm.</p><p>Ahora, crea un nuevo archivo <code>EnrutadorDeApp.js</code> dentro de la carpeta del enrutador con el siguiente contenido:</p><pre><code class="language-jsx">import React from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import Header from '../componentes/Header';
import AgregaLibro from '../componentes/AgregaLibro';
import ListaDeLibros from '../componentes/ListaDeLibros';

const EnrutadorDeApp = () =&gt; {
  return (
    &lt;BrowserRouter&gt;
      &lt;div&gt;
        &lt;Header /&gt;
        &lt;div className="main-content"&gt;
          &lt;Switch&gt;
            &lt;Route component={ListaDeLibros} path="/" exact={true} /&gt;
            &lt;Route component={AgregaLibro} path="/add" /&gt;
          &lt;/Switch&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/BrowserRouter&gt;
  );
};

export default EnrutadorDeApp;
</code></pre><p>Aquí, hemos configurado el enrutamiento para varios componentes como <code>ListaDeLibros</code> y <code>AgregaLibro</code> utilizando la biblioteca <code>react-router-dom</code>.</p><p>Ahora, abra el archivo <code>src/index.js</code> y agregue los siguientes contenidos dentro de él:</p><pre><code class="language-js">import React from 'react';
import ReactDOM from 'react-dom';
import EnrutadorDeApp from './enrutadores/EnrutadorDeApp';
import 'bootstrap/dist/css/bootstrap.min.css';
import './styles.scss';

ReactDOM.render(&lt;EnrutadorDeApp /&gt;, document.getElementById('root'));
</code></pre><p>Ahora, inicie la aplicación React ejecutando el siguiente comando desde la terminal:</p><pre><code class="language-js">yarn start
</code></pre><p>Verá la siguiente pantalla cuando acceda a la aplicación en <a href="http://localhost:3000/">http://localhost:3000/</a>.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/04/initial_screen.gif" class="kg-image" alt="initial_screen" width="600" height="400" loading="lazy"></figure><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/04/add_book.gif" class="kg-image" alt="add_book" width="600" height="400" loading="lazy"></figure><p>Como puede ver, podemos agregar correctamente el libro y mostrarlo en la consola.</p><p>Pero en lugar de iniciar sesión en la consola, agréguemoslo al almacenamiento local.</p><h2 id="c-mo-crear-un-hook-personalizado-para-almacenamiento-local"><strong>Cómo crear un hook personalizado para almacenamiento local</strong></h2><p>El almacenamiento local es increíble. Nos permite almacenar fácilmente datos de aplicaciones en el navegador y es una alternativa a las cookies para almacenar datos.</p><p>La ventaja de utilizar el almacenamiento local es que los datos se guardarán de forma permanente en la memoria caché del navegador hasta que los eliminemos manualmente para poder acceder a ellos incluso después de actualizar la página. Como sabrá, los datos almacenados en el estado React se perderán una vez que actualicemos la página.</p><p>Hay muchos casos de uso para el almacenamiento local, y uno de ellos es almacenar elementos del carrito de compras para que no se eliminen incluso si actualizamos la página.</p><p>Para agregar datos al almacenamiento local, usamos el método <code>setItem</code> proporcionando una clave y un valor:</p><pre><code class="language-js">localStorage.setItem(clave, valor)
</code></pre><blockquote>Tanto la clave como el valor deben ser una cadena. Pero también podemos almacenar el objeto JSON usando el método <code>JSON.stringify</code>.</blockquote><p>Cree un nuevo archivo <code>usaAlmacenamientoLocal.js</code> dentro de la carpeta de <code>hooks</code> con el siguiente contenido:</p><pre><code class="language-jsx">import { useState, useEffect } from 'react';

const usaAlmacenamientoLocal = (clave, valorInicial) =&gt; {
  const [valor, setValor] = useState(() =&gt; {
    try {
      const almacenamientoLocal = window.localStorage.getItem(clave);
      return almacenamientoLocal ? JSON.parse(lmacenamientoLocal) : initialValue;
    } catch (error) {
      return valorInicial;
    }
  });

  useEffect(() =&gt; {
    window.localStorage.setItem(key, JSON.stringify(valor));
  }, [clave, valor]);

  return [valor, setValor];
};

export default usaAlmacenamientoLocal;
</code></pre><p>Aquí, hemos usado un <code>usaAlmacenamientoLocal</code> hook que acepta una clave y un valor inicial.</p><p>Para declarar el estado usando el <code>useState</code> hook, estamos usando la <a href="https://es.reactjs.org/docs/hooks-reference.html#lazy-initialization">inicialización diferida</a>.</p><p>Por lo tanto, el código dentro de la función que se pasa a <code>useState</code> se ejecutará solo una vez, incluso si el <code>usaAlmacenamientoLocal</code> hook se llama varias veces en cada nueva representación de la aplicación.</p><p>Entonces, inicialmente estamos verificando si hay algún valor en el almacenamiento local con la <code>clave</code> proporcionada y devolvemos el valor al analizarlo usando el método <code>JSON.parse</code>:</p><pre><code class="language-js">try {
  const valorLocal = window.localStorage.getItem(clave);
  return valorLocal ? JSON.parse(valorLocal) : valorInicial;
} catch (error) {
  return valorInicial;
}
</code></pre><p>Luego, si hay algún cambio en la <code>clave</code> o el <code>valor</code>, actualizaremos el almacenamiento local:</p><pre><code class="language-js">useEffect(() =&gt; {
    window.localStorage.setItem(clave, JSON.stringify(valor));
}, [clave, valor]);

return [valor, setValor];
</code></pre><p>Luego, devolvemos el <code>valor</code> almacenado en el almacenamiento local y la función <code>setValor</code> a la que llamaremos para actualizar los datos del localStorage.</p><h2 id="c-mo-utilizar-el-hook-de-almacenamiento-local"><strong>Cómo utilizar el hook de almacenamiento local</strong></h2><p>Ahora, usemos este <code>usaAlmacenamientoLocal</code> hook para que podamos agregar o eliminar datos del almacenamiento local.</p><p>Abra el archivo <code>EnrutadorDeApp.js</code> y use el hook <code>usaAlmacenamientoLocal</code> dentro del componente:</p><pre><code class="language-js">import usaAlmacenamientoLocal from '../hooks/usaAlmacenamientoLocal';

const EnrutadorDeApp = () =&gt; {
 const [libros, setLibros] = usaAlmacenamientoLocal('libros', []);
 
 return (
  ...
 )
}
</code></pre><p>Ahora, necesitamos pasar los <code>libros</code> y <code>setLibros</code> como props al componente <code>AgregaLibro</code> para que podamos agregar el libro al almacenamiento local.</p><p>Así que cambia la ruta desde este código:</p><pre><code class="language-jsx">&lt;Route component={AgregaLibro} path="/add" /&gt;
</code></pre><p>al siguiente código:</p><pre><code class="language-jsx">&lt;Route
  render={(props) =&gt; (
    &lt;AgregaLibro {...props} libros={libros} setLibros={setLibros} /&gt;
  )}
  path="/add"
/&gt;
</code></pre><p>Aquí, estamos usando render props de representación para pasar los props predeterminados pasados por el enrutador React junto con los <code>libros</code> y <code>setLibros</code>.</p><p>Su archivo <code>EnrutadorDeApp.js</code> completo se verá así ahora:</p><pre><code class="language-jsx">import React from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import Header from '../componentes/Header';
import AgregaLibro from '../componentes/AgregaLibro';
import ListaDeLibros from '../componentes/ListaDeLibros';
import usaAlmacenamientoLocal from '../hooks/usaAlmacenamientoLocal';

const EnrutadorDeApp = () =&gt; {
  const [libros, setLibros] = usaAlmacenamientoLocal('libros', []);

  return (
    &lt;BrowserRouter&gt;
      &lt;div&gt;
        &lt;Header /&gt;
        &lt;div className="main-content"&gt;
          &lt;Switch&gt;
            &lt;Route component={BooksList} path="/" exact={true} /&gt;
            &lt;Route
              render={(props) =&gt; (
                &lt;AddBook {...props} libros={libros} setLibros={setLibros} /&gt;
              )}
              path="/add"
            /&gt;
          &lt;/Switch&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/BrowserRouter&gt;
  );
};

export default EnrutadorDeApp;
</code></pre><p>Now open <code>AgregaLibro.js</code> and replace its content with the following code:</p><pre><code class="language-jsx">import React from 'react';
import FormularioDeLibro from './FormularioDeLibro';

const AgregaLibro = ({ historia, libros, setLibros }) =&gt; {
  const handleOnSubmit = (libro) =&gt; {
    setLibros([libro, ...libros]);
    historia.push('/');
  };

  return (
    &lt;React.Fragment&gt;
      &lt;BookForm handleOnSubmit={handleOnSubmit} /&gt;
    &lt;/React.Fragment&gt;
  );
};

export default AgregaLibro;
</code></pre><p>Primero, estamos usando la sintaxis de desestructuración de ES6 para acceder a los props de <code>historia</code>, <code>libros</code> y <code>setLibros</code> en el componente.</p><p>React Router pasa automáticamente el prop de <code>historia</code> a cada componente mencionado en <code>&lt;Route /&gt;</code>. Estamos pasando los props <code>libros</code> y <code>setLibros</code> del archivo <code>EnrutadorDeApp.js</code>.</p><p>Estamos almacenando todos los libros agregados en un arreglo. Dentro del método <code>handleOnSubmit</code>, estamos llamando a la función <code>setLibros</code> pasando un arreglo agregando primero un libro recién agregado y luego distribuyendo todos los libros ya agregados en el arreglo de <code>libros</code> como se muestra a continuación:</p><pre><code class="language-js">setLibros([libro, ...libros]);
</code></pre><p>Aquí, primero agrego el <code>libro</code> recién agregado y luego distribuyo los <code>libros</code> ya agregados porque quiero que el último libro se muestre primero cuando mostremos la lista de libros más tarde.</p><p>Pero puedes cambiar el orden si quieres así:</p><pre><code class="language-js">setLibros([...libros, libro]);</code></pre><p>Esto agregará el libro recién agregado al final de todos los libros ya agregados.</p><p>Podemos usar el operador de propagación porque sabemos que los <code>libros</code> son un arreglo (ya que lo hemos inicializado en un arreglo vacío <code>[]</code> en el archivo <code>EnrutadorDeApp.js</code> como se muestra a continuación):</p><pre><code class="language-js"> const [libros, setLibros] = usaAlmacenamientoLocal('libros', []);
</code></pre><p>Luego, una vez que el libro se agrega al almacenamiento local llamando al método <code>setLibros</code>, dentro del método <code>handleOnSubmit</code> estamos redirigiendo al usuario a la página <code>Lista de libros</code> usando el método <code>historia.push</code>:</p><pre><code class="language-js">historia.push('/');
</code></pre><p>Ahora, verifiquemos si podemos guardar los libros en el almacenamiento local o no.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/04/added_local_storage.gif" class="kg-image" alt="added_local_storage" width="600" height="400" loading="lazy"></figure><p>Como puede ver, el libro se agrega correctamente al almacenamiento local (y puede confirmarlo en la pestaña de aplicaciones de las herramientas de desarrollo de Chrome).</p><h2 id="c-mo-mostrar-libros-agregados-en-el-interfaz-de-usuario"><strong>Cómo mostrar libros agregados en el interfaz de usuario</strong></h2><p>Ahora, mostremos los libros agregados en el interfaz de usuario en el menú <code>Lista de libros</code>.</p><p>Abra <code>EnrutadorDeApp.js</code> y pase los <code>libros</code> y <code>setLibros</code> como props al componente ListaDeLibros.</p><p>Su archivo <code>EnrutadorDeApp.js</code> se verá así ahora:</p><pre><code class="language-jsx">import React from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import Header from '../componentes/Header';
import AgregaLibro from '../componentes/AgregaLibro';
import ListaDeLibros from '../componentes/ListaDeLibros';
import usaAlmacenamientoLocal from '../hooks/usaAlmacenamientoLocal';

const EnrutadorDeApp = () =&gt; {
  const [libros, setLibros] = usaAlmacenamientoLocal('libros', []);

  return (
    &lt;BrowserRouter&gt;
      &lt;div&gt;
        &lt;Header /&gt;
        &lt;div className="main-content"&gt;
          &lt;Switch&gt;
            &lt;Route
              render={(props) =&gt; (
                &lt;BooksList {...props} libros={libros} setLibros={setLibros} /&gt;
              )}
              path="/"
              exact={true}
            /&gt;
            &lt;Route
              render={(props) =&gt; (
                &lt;AddBook {...props} libros={libros} setLibros={setLibros} /&gt;
              )}
              path="/add"
            /&gt;
          &lt;/Switch&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/BrowserRouter&gt;
  );
};

export default EnrutadorDeApp;
</code></pre><p>Aquí, acabamos de cambiar la primera ruta relacionada con el componente <code>ListaDeLibros</code>.</p><p>Ahora, crea un nuevo archivo <code>Libro.js</code> dentro de la carpeta de <code>componentes</code> con el siguiente contenido:</p><pre><code class="language-jsx">import React from 'react';
import { Button, Card } from 'react-bootstrap';

const Libro = ({
  id,
  nombrelibro,
  autor,
  precio,
  cantidad,
  fecha,
  manejarEliminarLibro
}) =&gt; {
  return (
    &lt;Card style={{ width: '18rem' }} className="book"&gt;
      &lt;Card.Body&gt;
        &lt;Card.Title className="book-title"&gt;{nombrelibro}&lt;/Card.Title&gt;
        &lt;div className="book-details"&gt;
          &lt;div&gt;Autor: {autor}&lt;/div&gt;
          &lt;div&gt;Cantidad: {cantidad} &lt;/div&gt;
          &lt;div&gt;Precio: {precio} &lt;/div&gt;
          &lt;div&gt;Fecha: {new Date(date).toDateString()}&lt;/div&gt;
        &lt;/div&gt;
        &lt;Button variant="primary"&gt;Editar&lt;/Button&gt;{' '}
        &lt;Button variant="danger" onClick={() =&gt; manejarEliminarLibro(id)}&gt;
          Eliminar
        &lt;/Button&gt;
      &lt;/Card.Body&gt;
    &lt;/Card&gt;
  );
};

export default Libro;
</code></pre><p>Ahora, abre el archivo <code>ListaDeLibros.js</code> y reemplaza su contenido con el siguiente código:</p><pre><code class="language-jsx">import React from 'react';
import _ from 'lodash';
import Libro from './Libro';

const ListaDeLibros = ({ libros, setLibros }) =&gt; {

  const manejarEliminarLibro = (id) =&gt; {
    setLibros(libros.filter((libro) =&gt; libro.id !== id));
  };

  return (
    &lt;React.Fragment&gt;
      &lt;div className="book-list"&gt;
        {!_.isEmpty(libros) ? (
          libros.map((libro) =&gt; (
            &lt;Libro key={libro.id} {...libro} manejarEliminarLibro={manejarEliminarLibro} /&gt;
          ))
        ) : (
          &lt;p className="message"&gt;No hay libros disponibles. Por favor agregue algunos libros.&lt;/p&gt;
        )}
      &lt;/div&gt;
    &lt;/React.Fragment&gt;
  );
};

export default ListaDeLibros;
</code></pre><p>En este archivo, estamos recorriendo los <code>libros</code> usando el método de <code>map</code> de arreglo y pasándolos como apoyo al componente <code>Libro</code>.</p><p>Tenga en cuenta que también estamos pasando la función <code>manejarEliminarLibro</code> como prop para que podamos eliminar cualquier libro que queramos.</p><p>Dentro de la función <code>manejarEliminarLibro</code>, estamos llamando a la función <code>setLibros</code> usando el método de <code>filter</code> de arreglo para mantener solo los libros que no coinciden con la <code>id</code> del libro proporcionada.</p><pre><code class="language-js">const manejarEliminarLibro = (id) =&gt; {
    setLibros(libros.filter((libro) =&gt; libro.id !== id));
};
</code></pre><p>Ahora, si verifica la aplicación visitando <a href="http://localhost:3000/">http://localhost:3000/</a>, podrá ver el libro agregado en el interfaz de usuario.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/04/list_page.png" class="kg-image" alt="list_page" width="600" height="400" loading="lazy"></figure><p>Agreguemos otro libro para verificar todo el flujo.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/04/add_delete.gif" class="kg-image" alt="add_delete" width="600" height="400" loading="lazy"></figure><p>Como puede ver, cuando agregamos un nuevo libro, somos redirigidos a la página de la lista donde podemos eliminar el libro. Puede ver que se elimina instantáneamente de el interfaz de usuario y del almacenamiento local.</p><p>Además cuando refrescamos la página los datos no se pierden. Ese es el poder del almacenamiento local.</p><h2 id="c-mo-editar-un-libro"><strong>Cómo editar un libro</strong></h2><p>Ahora tenemos la funcionalidad de agregar y eliminar para los libros. Agreguemos una forma de editar los libros que tenemos.</p><p>Abra <code>Libro.js</code> y cambie el siguiente código:</p><pre><code class="language-jsx">&lt;Button variant="primary"&gt;Editar&lt;/Button&gt;{' '}
</code></pre><p>a este código:</p><pre><code class="language-jsx">&lt;Button variant="primary" onClick={() =&gt; historia.push(`/edit/${id}`)}&gt;
  Editar
&lt;/Button&gt;{' '}
</code></pre><p>Aquí, hemos agregado un controlador <code>onClick</code> para redirigir al usuario a la ruta <code>/edit/id_del_libro</code> cuando hacemos clic en el botón editar.</p><p>Pero no tenemos acceso al objeto <code>historia</code> en el componente <code>Libro</code> porque la propiedad historia se pasa solo a los componentes que se mencionan en la <code>&lt;Route /&gt;</code>.</p><p>Estamos renderizando el componente <code>Libro</code> dentro del componente <code>ListaDeLibros</code> para que podamos tener acceso a la <code>historia</code> solo dentro del componente <code>ListaDeLibros</code>. Luego podemos pasarlo como prop al componente <code>Libro</code>.</p><p>Pero en lugar de eso, el React router proporciona una manera fácil de usar el <code>useHistory</code> hook.</p><p>Importe el <code>useHistory</code> hook en la parte superior del archivo <code>Libro.js</code>:</p><pre><code class="language-js">import { useHistory } from 'react-router-dom';
</code></pre><p>y dentro del componente <code>Libro</code>, llame al <code>useHistory</code> hook.</p><pre><code class="language-js">const Book = ({
  nombrelibro,
  autor,
  precio,
  cantidad,
  fecha,
  manejarEliminarLibro
}) =&gt; {
  const historia = useHistory();
  ...
}
</code></pre><p>Ahora tenemos acceso al objeto de <code>historia</code> dentro del componente <code>Libro</code>.</p><p>Todo su archivo <code>Libro.js</code> se ve así ahora:</p><pre><code class="language-jsx">import React from 'react';
import { Button, Card } from 'react-bootstrap';
import { useHistory } from 'react-router-dom';

const Libro = ({
  id,
  nombrelibro,
  autor,
  precio,
  cantidad,
  fecha,
  manejarEliminarLibro
}) =&gt; {
  const historia = useHistory();

  return (
    &lt;Card style={{ width: '18rem' }} className="book"&gt;
      &lt;Card.Body&gt;
        &lt;Card.Title className="book-title"&gt;{nombrelibro}&lt;/Card.Title&gt;
        &lt;div className="book-details"&gt;
          &lt;div&gt;Autor: {autor}&lt;/div&gt;
          &lt;div&gt;Cantidad: {cantidad} &lt;/div&gt;
          &lt;div&gt;Precio: {precio} &lt;/div&gt;
          &lt;div&gt;Fecha: {new Date(date).toDateString()}&lt;/div&gt;
        &lt;/div&gt;
        &lt;Button variant="primary" onClick={() =&gt; historia.push(`/edit/${id}`)}&gt;
          Editar
        &lt;/Button&gt;{' '}
        &lt;Button variant="danger" onClick={() =&gt; manejarEliminarLibro(id)}&gt;
          Eliminar
        &lt;/Button&gt;
      &lt;/Card.Body&gt;
    &lt;/Card&gt;
  );
};

export default Libro;
</code></pre><p>Crea un nuevo archivo llamado <code>EditarLibro.js</code> dentro de la carpeta de <code>componentes</code> con el siguiente contenido:</p><pre><code class="language-jsx">import React from 'react';
import FormularioDeLibro from './FormularioDeLibro';
import { useParams } from 'react-router-dom';

const EditarLibro = ({ historia, libros, setLibros }) =&gt; {
  const { id } = useParams();
  const libroParaEditar = libros.find((libro) =&gt; libro.id === id);

  const handleOnSubmit = (libro) =&gt; {
    const librosFiltrados = books.filter((libro) =&gt; libro.id !== id);
    setLibros([libro, ...librosFiltrados]);
    historia.push('/');
  };

  return (
    &lt;div&gt;
      &lt;FormularioDeLibro libro={libroParaEditar} handleOnSubmit={handleOnSubmit} /&gt;
    &lt;/div&gt;
  );
};

export default EditarLibro;
</code></pre><p>Aquí, para el controlador <code>onClick</code> del botón Editar, estamos redirigiendo al usuario a la ruta <code>/edit/alguna_id</code>, pero esa ruta aún no existe. Así que vamos a crear eso primero.</p><p>Abra <code>EnrutadorDeApp.js</code> y antes de la etiqueta final del <code>Switch</code> agregue dos rutas más:</p><pre><code class="language-jsx">&lt;Switch&gt;
...
&lt;Route
  render={(props) =&gt; (
    &lt;EditarLibro {...props} libros={libros} setLibros={setLibros} /&gt;
  )}
  path="/edit/:id"
/&gt;
&lt;Route component={() =&gt; &lt;Redirect to="/" /&gt;} /&gt;
&lt;/Switch&gt;
</code></pre><p>La primera Ruta es para el componente <code>EditarLibro</code>. Aquí, la ruta se define como <code>/edit/:id</code> donde <code>:id</code> representa cualquier id aleatorio.</p><p>La segunda ruta es para manejar todas las demás rutas que no coinciden con ninguna de las rutas mencionadas.</p><p>Entonces, si accedemos a cualquier ruta aleatoria como <code>/ayuda</code> o <code>/contacto</code>, redirigiremos al usuario a la ruta <code>/</code> que es el componente <code>ListaDeLibros</code>.</p><p>Todo su archivo <code>EnrutadorDeApp.js</code> se ve así ahora:</p><pre><code class="language-jsx">import React from 'react';
import { BrowserRouter, Switch, Route } from 'react-router-dom';
import Header from '../componentes/Header';
import AgregaLibro from '../componentes/AgregaLibro';
import ListaDeLibros from '../componentes/ListaDeLibros';
import usaAlmacenamientoLocal from '../hooks/usaAlmacenamientoLocal';

const EnrutadorDeApp = () =&gt; {
  const [libros, setLibros] = usaAlmacenamientoLocal('libros', []);

  return (
    &lt;BrowserRouter&gt;
      &lt;div&gt;
        &lt;Header /&gt;
        &lt;div className="main-content"&gt;
          &lt;Switch&gt;
            &lt;Route
              render={(props) =&gt; (
                &lt;ListaDeLibros {...props} libros={libros} setLibros={setLibros} /&gt;
              )}
              path="/"
              exact={true}
            /&gt;
            &lt;Route
              render={(props) =&gt; (
                &lt;AgregaLibro {...props} libros={libros} setLibros={setLibros} /&gt;
              )}
              path="/add"
            /&gt;
            &lt;Route
              render={(props) =&gt; (
                &lt;EditarLibro {...props} libros={libros} setLibros={setLibros} /&gt;
              )}
              path="/edit/:id"
            /&gt;
            &lt;Route component={() =&gt; &lt;Redirect to="/" /&gt;} /&gt;
          &lt;/Switch&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/BrowserRouter&gt;
  );
};

export default EnrutadorDeApp;
</code></pre><p>Ahora, verifiquemos la funcionalidad de editar de la aplicación.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/04/edit_book.gif" class="kg-image" alt="edit_book" width="600" height="400" loading="lazy"></figure><p>Como puede ver, pudimos editar el libro correctamente. Vamos a entender cómo funciona esto.</p><p>Primero, dentro del archivo <code>EnrutadorDeApp.js</code> tenemos una ruta como esta:</p><pre><code class="language-jsx">&lt;Route
  render={(props) =&gt; (
    &lt;EditarLibro {...props} libros={libros} setLibros={setLibros} /&gt;
  )}
  path="/edit/:id"
/&gt;
</code></pre><p>y dentro del archivo <code>Libro.js</code> tenemos un botón de editar como este:</p><pre><code class="language-jsx">&lt;Button variant="primary" onClick={() =&gt; historia.push(`/edit/${id}`)}&gt;
  Editar
&lt;/Button&gt;
</code></pre><p>Entonces, cada vez que hacemos clic en el botón Editar para cualquiera de los libros, estamos redirigiendo al usuario al componente <code>EditarLibro</code> utilizando el método <code>historia.push</code> al pasar la identificación del libro que se editará.</p><p>Luego, dentro del componente <code>EditarLibro</code>, estamos usando el enlace useParams proporcionado por <code>react-router-dom</code> para acceder a <code>props.params.id</code>.</p><p>Así que las dos líneas siguientes son idénticas:</p><pre><code class="language-js">const { id } = useParams();

// la línea de código de arriba es igual que el código de abajo

const { id } = props.match.params;
</code></pre><p>Una vez que hemos obtenido esa <code>id</code>, estamos usando el método de <code>find</code> de arreglo para encontrar el libro en particular de la lista de libros con la <code>id</code> proporcionada coincidente.</p><pre><code class="language-js">const libroParaEditar = libros.find((libro) =&gt; libro.id === id);
</code></pre><p>y este libro en particular lo estamos pasando al componente <code>FormularioDeLibro</code> como prop de <code>libro</code>:</p><pre><code class="language-jsx">&lt;FormularioDeLibro libro={libroParaEditar} handleOnSubmit={handleOnSubmit} /&gt;
</code></pre><p>Dentro del componente <code>FormularioDeLibro</code>, hemos definido el estado como se muestra a continuación:</p><pre><code class="language-js">const [libro, setLibro] = useState({
  nombrelibro: props.libro ? props.libro.nombrelibro : '',
  autor: props.libro ? props.libro.autor : '',
  cantidad: props.libro ? props.libro.cantidad : '',
  precio: props.libro ? props.libro.precio : '',
  fecha: props.libro ? props.libro.fecha : ''
});</code></pre><p>Aquí, estamos comprobando si existe el prop del <code>libro</code>. En caso afirmativo, estamos usando los detalles del libro pasado como prop; de lo contrario, estamos inicializando el estado con un valor vacío <code>('')</code> para cada propiedad.</p><p>Y cada uno de los elementos de entrada ha proporcionado un prop de <code>valor</code> que estamos configurando desde el estado como este:</p><pre><code class="language-jsx">&lt;Form.Control
  ...
  valor={nombrelibro}
  ...
/&gt;
</code></pre><p>Pero podemos mejorar un poco la sintaxis de <code>useState</code> dentro del componente <code>FormularioDeLibro</code>.</p><p>En lugar de configurar directamente un objeto para el <code>useState</code> hook, podemos usar la inicialización diferida como se hizo en el archivo <code>usaAlmacenamientoLocal.js</code>.</p><p>Así que cambia el siguiente código:</p><pre><code class="language-js">const [libro, setLibro] = useState({
  nombrelibro: props.libro ? props.libro.nombrelibro : '',
  autor: props.libro ? props.libro.autor : '',
  cantidad: props.libro ? props.libro.cantidad : '',
  precio: props.libro ? props.libro.precio : '',
  fecha: props.libro ? props.libro.fecha : ''
});
</code></pre><p>a este código:</p><pre><code class="language-js">const [libro, setLibro] = useState(() =&gt; {
  return {
    nombrelibro: props.libro ? props.libro.nombrelibro : '',
    autor: props.libro ? props.libro.autor : '',
    cantidad: props.libro ? props.libro.cantidad : '',
    precio: props.libro ? props.libro.precio : '',
    fecha: props.libro ? props.libro.fecha : ''
  };
});</code></pre><p>Debido a este cambio, el código para establecer el estado no se ejecutará en cada nueva representación de la aplicación. Solo se ejecutará una vez cuando se monte el componente.</p><blockquote>Tenga en cuenta que la nueva representación del componente ocurre en cada cambio de estado o prop.</blockquote><p>Si revisa la aplicación, verá que la aplicación funciona exactamente como antes sin ningún problema. Pero acabamos de mejorar un poco el rendimiento de la aplicación.</p><h2 id="c-mo-usar-el-api-de-contexto-de-react"><strong>Cómo usar el API de contexto de React</strong></h2><p>Ahora hemos terminado de desarrollar toda la funcionalidad de la aplicación. Pero si revisas el archivo <code>EnrutadorDeApp.js</code>, verás que cada Ruta se ve un poco complicada. Esto se debe a que estamos pasando los mismos <code>libros</code> y props de <code>setLibros</code> a cada uno de los componentes mediante el patrón de render props.</p><p>Entonces podemos usar la API React Context para simplificar este código.</p><blockquote>Tenga en cuenta que este es un paso opcional. No necesitas usar el Context API ya que estamos pasando los accesorios solo un nivel de profundidad y el código actual funciona perfectamente bien y no hemos usado ningún enfoque incorrecto para pasar los props.</blockquote><p>Pero solo para simplificar el código del enrutador y darle una idea sobre cómo aprovechar el poder de el API React Context, la usaremos en nuestra aplicación.</p><p>Crea un nuevo archivo <code>ContextoDeLosLibros.js</code> dentro de la carpeta <code>contexto</code> con el siguiente contenido:</p><pre><code class="language-js">import React from 'react';

const ContextoDeLosLibros = React.createContext();

export default ContextoDeLosLibros;
</code></pre><p>Ahora, dentro del archivo EnrutadorDeApp.js, importe el contexto exportado anterior.</p><pre><code class="language-js">import ContextoDeLosLibros from '../contexto/ContextoDeLosLibros';
</code></pre><p>y reemplace el componente EnrutadorDeApp con el siguiente código:</p><pre><code class="language-jsx">const EnrutadorDeApp = () =&gt; {
  const [libros, setLibros] = usaAlmacenamientoLocal('libros', []);

  return (
    &lt;BrowserRouter&gt;
      &lt;div&gt;
        &lt;Header /&gt;
        &lt;div className="main-content"&gt;
          &lt;ContextoDeLosLibros.Provider value={{ libros, setLibros }}&gt;
            &lt;Switch&gt;
              &lt;Route component={ListaDeLibros} path="/" exact={true} /&gt;
              &lt;Route component={AgregaLibro} path="/add" /&gt;
              &lt;Route component={EditarLibro} path="/edit/:id" /&gt;
              &lt;Route component={() =&gt; &lt;Redirect to="/" /&gt;} /&gt;
            &lt;/Switch&gt;
          &lt;/ContextoDeLosLibros.Provider&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/BrowserRouter&gt;
  );
};
</code></pre><p>Aquí, hemos vuelto a convertir el patrón de render props a las rutas normales y hemos agregado el bloque <code>Switch</code> completo dentro del componente <code>ContextoDeLosLibros.Provider</code> de esta manera:</p><pre><code class="language-jsx">&lt;ContextoDeLosLibros.Provider value={{ libros, setLibros }}&gt;
 &lt;Switch&gt;
 ...
 &lt;/Switch&gt;
&lt;/ContextoDeLosLibros.Provider&gt;
</code></pre><p>Aquí, para el componente <code>ContextoDeLosLibros.Provider</code>, proporcionamos un prop de <code>value</code> al pasar los datos a los que queremos acceder dentro de los componentes mencionados en la Route.</p><p>Entonces, ahora, cada componente declarado como parte de Route podrá acceder a los <code>libros</code> y <code>setLibros</code> a través de el Context API.</p><p>Ahora, abra el archivo <code>ListaDeLibros.js</code> y elimine los <code>libros</code> y los props de <code>setLibros</code> que están desestructurados, ya que ya no estamos pasando los props directamente.</p><p>Importe el <code>ContextoDeLosLibros</code> y <code>useContext</code> en la parte superior del archivo:</p><pre><code class="language-js">import React, { useContext } from 'react';
import ContextoDeLosLibros from '../contexto/ContextoDeLosLibros';
</code></pre><p>Y encima de la función <code>manejarEliminarLibro</code>, agrega el siguiente código:</p><pre><code class="language-js">const { libros, setLibros } = useContext(ContextoDeLosLibros);
</code></pre><p>Aquí, estamos sacando los <code>libros</code> y los props de <code>setLibros</code> del <code>ContextoDeLosLibros</code> usando el <code>useContext</code> hook.</p><p>Todo su archivo <code>ListaDeLibros.js</code> se verá así:</p><pre><code class="language-jsx">import React, { useContext } from 'react';
import _ from 'lodash';
import Libro from './Libro';
import ContextoDeLosLibros from '../contexto/ContextoDeLosLibros';

const ListaDeLibros = () =&gt; {
  const { libros, setLibros } = useContext(ContextoDeLosLibros);

  const manejarEliminarLibro = (id) =&gt; {
    setLibros(libros.filter((libro) =&gt; libro.id !== id));
  };

  return (
    &lt;React.Fragment&gt;
      &lt;div className="book-list"&gt;
        {!_.isEmpty(libros) ? (
          libros.map((libro) =&gt; (
            &lt;Libro key={libro.id} {...libro} manejarEliminarLibro={manejarEliminarLibro} /&gt;
          ))
        ) : (
          &lt;p className="message"&gt;No hay libros disponibles. Por favor agregue algunos libros.&lt;/p&gt;
        )}
      &lt;/div&gt;
    &lt;/React.Fragment&gt;
  );
};

export default ListaDeLibros;
</code></pre><p>Ahora, haz cambios similares en el archivo <code>AgregaLibro.js</code>.</p><p>Todo su archivo <code>AgregaLibro.js</code> se verá así:</p><pre><code class="language-jsx">import React, { useContext } from 'react';
import FormularioDeLibro from './FormularioDeLibro';
import ContextoDeLosLibros from '../contexto/ContextoDeLosLibros';

const AgregaLibro = ({ historia }) =&gt; {
  const { libros, setLibros } = useContext(ContextoDeLosLibros);

  const handleOnSubmit = (libro) =&gt; {
    setLibros([libro, ...libros]);
    historia.push('/');
  };

  return (
    &lt;React.Fragment&gt;
      &lt;FormularioDeLibro handleOnSubmit={handleOnSubmit} /&gt;
    &lt;/React.Fragment&gt;
  );
};

export default AgregaLibro;
</code></pre><p>Tenga en cuenta que aquí, todavía estamos usando la desestructuración para el prop de <code>historia</code>. Solo hemos eliminado los <code>libros</code> y <code>setLibros</code> de la sintaxis de desestructuración.</p><p>Ahora, haz cambios similares en el archivo <code>EditarLibro.js</code>.</p><p>Todo su archivo <code>EditarLibro.js</code> se verá así:</p><pre><code class="language-jsx">import React, { useContext } from 'react';
import FormularioDeLibro from './FormularioDeLibro';
import { useParams } from 'react-router-dom';
import ContextoDeLosLibros from '../contexto/ContextoDeLosLibros';

const EditarLibro = ({ historia }) =&gt; {
  const { libros, setLibros } = useContext(ContextoDeLosLibros);
  const { id } = useParams();
  const libroParaEditar = libros.find((libro) =&gt; libro.id === id);

  const handleOnSubmit = (libro) =&gt; {
    const librosFiltrados = libros.filter((libro) =&gt; libro.id !== id);
    setLibros([libro, ...librosFiltrados]);
    historia.push('/');
  };

  return (
    &lt;div&gt;
      &lt;FormularioDeLibro libro={libroParaEditar} handleOnSubmit={handleOnSubmit} /&gt;
    &lt;/div&gt;
  );
};

export default EditarLibro;
</code></pre><p>Si revisa la aplicación, verá que funciona exactamente como antes, pero ahora estamos usando la React Context API.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/04/edit_delete.gif" class="kg-image" alt="edit_delete" width="600" height="400" loading="lazy"></figure><h3 id="-gracias-por-leer-">¡Gracias por leer!</h3><p>Puedes encontrar el código completo de esta aplicación en este <a href="https://github.com/myogeshchavan97/react-book-management-app">repositorio</a>.</p><p>¿Quieres mantenerte al día con el contenido regular sobre JavaScript, React, Node.js? <a href="https://www.linkedin.com/in/yogesh-chavan97/?original_referer=">Sígueme en LinkedIn</a>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Tutorial de la rama remota Git Checkout ]]>
                </title>
                <description>
                    <![CDATA[ Git es una herramienta de control de versiones que le permite mantener y ver diferentes versiones de su aplicación. Cuando una nueva actualización rompe su aplicación, Git le permite revertir esos cambios a la versión anterior. Además del control de versiones, Git le permite trabajar en múltiples entornos al mismo ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/tutorial-de-la-rama-remota-git-checkout/</link>
                <guid isPermaLink="false">63cb2378700708073437bf6e</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vanessa Pineiro Morales ]]>
                </dc:creator>
                <pubDate>Tue, 24 Jan 2023 18:44:25 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/01/Screen-Shot-2023-01-20-at-7.10.52-PM.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/git-checkout-remote-branch-tutorial/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Git Checkout Remote Branch Tutorial</a>
      </p><p>Git es una herramienta de control de versiones que le permite mantener y ver diferentes versiones de su aplicación. Cuando una nueva actualización rompe su aplicación, Git le permite revertir esos cambios a la versión anterior.</p><p>Además del control de versiones, Git le permite trabajar en múltiples entornos al mismo tiempo. Múltiples entornos en este contexto significa <strong>ramas</strong>.</p><h2 id="-por-qu-necesitas-ramas"><strong>¿Por qué necesitas ramas?</strong></h2><p>Cuando trabajes con git, tendrás un entorno maestro (también llamado principal) (rama). Esta rama en particular contiene el código fuente que se implementa cuando su aplicación está lista para la producción.</p><p>Cuando desees actualizar su aplicación, también puedes agregar más cambios (commits) a esta rama. Para cambios menores, esto puede no ser un gran problema, pero para cambios grandes, hacer esto no es lo ideal. Y es por eso que existen otras ramas.</p><p>Para crear y usar una nueva rama, usa el siguiente comando en tu terminal en el directorio del proyecto:</p><pre><code class="language-shell"># crear una nueva rama
git branch rama-nombre
# cambiar el ambiente a la nueva rama
git checkout rama-nombre
</code></pre><p>En esta nueva rama, puede crear los nuevos cambios. Luego, cuando hayas terminado, puedes combinarlos con la rama maestra.</p><p>Otro beneficio de las ramas es que permiten que varios desarrolladores trabajen en el mismo proyecto simultáneamente. Si tienes varios desarrolladores trabajando en la misma rama maestra, puede ser desastroso. Tiene demasiados cambios entre el código de cada desarrollador, y esto generalmente termina en conflictos de combinación.</p><p>Con Git, puede saltar a otra rama (otro entorno) y realizar cambios allí, mientras se trabaja en otras ramas.</p><h2 id="-qu-significa-rama-remota-de-git-checkout"><strong>¿Qué significa rama remota de Git Checkout?</strong></h2><p>Cuando comienzas un proyecto con Git, obtiene dos entornos: la rama maestra local (que existe en su computadora) y la rama maestra remota (que existe en una plataforma compatible con Git como GitHub).</p><p>Puedes enviar cambios desde la rama principal local a la rama principal remota y también extraer cambios de la rama remota.</p><p>Cuando creas una rama localmente, solo existe localmente hasta que se envía a GitHub, donde se convierte en la rama remota. Esto se muestra en el siguiente ejemplo:</p><pre><code class="language-shell"># crear una nueva rama
git branch nueva-rama
# cambiar el ambiente a la nueva rama
git checkout nueva-rama
# crear un cambio
touch nuevo-archivo.js
# cometer el cambio
git add .
git commit -m "añadir nuevo archivo"
# empujar a una nueva rama
git push --set-upstream origin nueva-rama
</code></pre><p>Del ejemplo anterior, <code>origin nueva-rama</code> se convierte en la rama remota. Como habrás notado, creamos una nueva rama y confirmamos un cambio en ella antes de pasar a la nueva rama remota.</p><p>Pero, ¿qué pasaría si la rama remota ya existiera y quisiéramos llevar la rama y todos sus cambios a nuestro entorno local?</p><p>Ahí es donde hacemos una "Rama Remota de Git Checkout".</p><h2 id="c-mo-hacer-git-checkout-en-una-rama-remota">Cómo hacer Git Checkout en una rama remota</h2><p>Digamos que hay una rama remota creada por otro desarrollador y desea extraer esa rama. Así es como lo haces:</p><h3 id="1-recuperar-todas-las-ramas-remotas"><strong>1. Recuperar todas las ramas remotas</strong></h3><pre><code class="language-shell">git fetch origin
</code></pre><p>Esto recupera todas las ramas remotas del repositorio. <code>origin</code> es el nombre remoto al que se dirige. Entonces, si tenía un nombre remoto <code>upstream</code>, puedes llamar a <code>git fetch upstream</code>.</p><h3 id="2-enumera-las-ramas-disponibles-para-checkout"><strong>2. Enumera las ramas disponibles para checkout</strong></h3><p>Para ver las ramas disponibles para checkout, ejecute lo siguiente:</p><pre><code class="language-shell">git branch -a
</code></pre><p>El resultado de este comando es la lista de ramas disponibles para checkout. Para las ramas remotas, las encontrará con el prefijo <code>remotes/origin</code>.</p><h3 id="3-obtener-cambios-de-una-rama-remota"><strong>3. Obtener cambios de una rama remota</strong></h3><p>Tenga en cuenta que no puedes hacer cambios directamente en una rama remota. Por lo tanto, necesitas una copia de esa rama. Digamos que deseas copiar <code>fix-failing-tests</code> de la rama remota, así es como lo harías:</p><pre><code class="language-shell">git checkout -b fix-failing-tests origin/fix-failing-tests
</code></pre><p>Lo que esto hace es:</p><ul><li>crea una nueva rama llamada <code>fix-failing-tests</code></li><li><code>checkout</code> esa rama</li><li>extrae los cambios desde el origin/fix-failing-tests a esa rama</li></ul><p>Y ahora tienes una copia de esa rama remota. Además, puedes enviar confirmaciones a esa rama remota. Por ejemplo, puedes empujar un nuevo compromiso así:</p><pre><code class="language-shell">touch nuevo-archivo.js
git add .
git commit -m "añadir nuevo archivo"
git push
</code></pre><p>Esto empujará los cambios comprometidos a <code>origin/fix-failing-tests</code>. Si te diste cuenta, no tuvimos que especificar dónde estábamos enviando los cambios (como <code>git push origin fix-failing-tests</code>). Eso es porque git configura automáticamente la rama local para rastrear la rama remota.</p><h2 id="conclusi-n">Conclusión</h2><p>La ramificación de Git facilita mucho la colaboración durante el desarrollo de aplicaciones.</p><p>Con las ramas, diferentes desarrolladores pueden trabajar fácilmente en diferentes partes de la aplicación simultáneamente.</p><p>Con la rama remota de Checkout, la colaboración se vuelve incluso más fluida, ya que los desarrolladores también pueden copiar ramas remotas localmente en sus sistemas, realizar cambios y enviarlos a las ramas remotas.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo Construir una Aplicación de Chat en Tiempo Real en Node.js Usando Express, Mongoose y Socket.io ]]>
                </title>
                <description>
                    <![CDATA[ En este tutorial, utilizaremos la plataforma Node.js para crear una aplicación de chat en tiempo real que envíe y muestre mensajes a un destinatario al instante sin actualizar la página. Usaremos el framework de JavaScript Express.js y las bibliotecas Mongoose y Socket.io para lograr esto. Antes de comenzar, echemos un ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-construir-una-aplicacion-de-chat-en-tiempo-real-en-node-js-usando-express-mongoose-and-socket-io/</link>
                <guid isPermaLink="false">63ca76c9700708073437b56d</guid>
                
                    <category>
                        <![CDATA[ Node.js ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vanessa Pineiro Morales ]]>
                </dc:creator>
                <pubDate>Tue, 24 Jan 2023 02:46:39 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/01/1-c4mV8Ppc8oe42XVQHfsjQw.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/simple-chat-application-in-node-js-using-express-mongoose-and-socket-io-ee62d94f5804/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to build a real time chat application in Node.js using Express, Mongoose and Socket.io</a>
      </p><p>En este tutorial, utilizaremos la plataforma Node.js para crear una <strong>aplicación de chat en tiempo real</strong> que envíe y muestre mensajes a un destinatario al instante sin actualizar la página. Usaremos el framework de JavaScript Express.js y las bibliotecas Mongoose y Socket.io para lograr esto.</p><p>Antes de comenzar, echemos un vistazo rápido a los conceptos básicos de Node.js</p><h3 id="node-js"><strong><strong><strong>Node.js</strong></strong></strong></h3><p><a href="https://es.wikipedia.org/wiki/Node.js">Node.js</a> es un entorno de tiempo de ejecución de JavaScript, de código abierto y multiplataforma que ejecuta código JavaScript fuera del navegador. La ventaja más importante de usar Node es que podemos usar JavaScript como lenguaje tanto de front-end como de back-end.</p><p>Como sabemos, JavaScript se usó principalmente para secuencias de comandos del lado del cliente, en las que las secuencias de comandos se incrustaron en el HTML de una página web y se ejecutaron en el lado del cliente mediante un motor de JavaScript en el navegador web del usuario.</p><p>Node.js permite a los desarrolladores usar JavaScript para escribir herramientas de línea de comandos y para secuencias de comandos del lado del servidor —ejecutando secuencias de comandos del lado del servidor para producir contenido de página web dinámico antes de que la página se envíe al navegador web del usuario.</p><p>Para instalar node:</p><p><a href="https://nodejs.org/es/download/">https://nodejs.org/es/download</a>/</p><p>Aunque el node tiene un solo subproceso, aún es más rápido usar funciones asíncronas. Por ejemplo, Node puede procesar otras cosas mientras se lee un archivo del disco o mientras se espera que se complete una solicitud HTTP. El comportamiento asincrónico se puede implementar mediante devoluciones de callback. Además, JavaScript funciona bien con bases de datos JSON y No-SQL.</p><h3 id="m-dulos-npm"><strong>Módulos NPM</strong></h3><p>Nodejs permite incluir en la aplicación los módulos de las librerías. Estos módulos pueden ser módulos definidos por el usuario o de terceros.</p><p>Los módulos de terceros se pueden instalar con el siguiente comando:</p><pre><code class="language-bash">npm install nombre_del_módulo</code></pre><p>y los módulos instalados se pueden usar usando la función <strong>require()</strong>:</p><pre><code class="language-js">var módulo = require(‘nombre_del_módulo’)</code></pre><p>En las aplicaciones de Node, usaremos un archivo package.json para mantener las versiones del módulo. Este archivo se puede crear con este comando:</p><pre><code class="language-bash">npm init</code></pre><p>y los paquetes deben instalarse de la siguiente manera:</p><pre><code class="language-bash">npm install -s nombre_del_módulo</code></pre><p>Hay muchos frameworks que se pueden agregar como módulos a nuestra aplicación Node. Estos se explicarán más adelante según sea necesario.</p><h3 id="aplicaci-n-de-chat-simple"><strong>Aplicación de Chat Simple</strong></h3><p>La aplicación debe permitir que varios usuarios chateen juntos. Los mensajes deben actualizarse sin refrescar la página. Para simplificar, evitaremos la parte de autenticación.</p><p>Podemos empezar por crear un nuevo directorio de proyecto y pasar a él. Luego podemos iniciar nuestro proyecto con el siguiente comando:</p><pre><code class="language-bash">npm init</code></pre><p>Esto nos pedirá que ingresemos detalles sobre nuestro proyecto.</p><p>Después de esto, se creará un archivo <strong>package.json</strong>:</p><pre><code class="language-json">{
 “name”: “test”,
 “version”: “1.0.0”,
 “description”: “”,
 “main”: “index.js”,
 “scripts”: {
 “test”: “echo \”Error: no test specified\” &amp;&amp; exit 1"
 },
 “author”: “”,
 “license”: “ISC”
}</code></pre><p>Nuestro directorio de aplicaciones ya está configurado.</p><p>Lo primero que necesitamos crear es un servidor. Para crear eso, utilizaremos un framework llamado<strong> Express</strong>.</p><h4 id="express-js"><strong><strong><strong>Express.js</strong></strong></strong></h4><p>Express.js, o simplemente Express, es un framework de aplicación web para Node.js. <a href="https://expressjs.com/es/">Express ofrece </a><a href="https://expressjs.com/es/">un sólido conjunto de características para aplicaciones web y móviles</a>. Express ofrece una capa delgada de características fundamentales de aplicaciones web, sin encubrir las características de Node.js.</p><p>Instalaremos Express.js usando el siguiente comando:</p><pre><code class="language-bash">npm install -s express</code></pre><p>Dentro del archivo package.json se agregará una nueva línea:</p><pre><code class="language-json">dependencies”: {
 “express”: “⁴.16.3”
 }</code></pre><p>A continuación, crearemos un archivo<strong> server.js</strong>.</p><p>En este archivo necesitamos requerir Express y crear una referencia a una variable desde una instancia de Express. Los contenidos estáticos como HTML, CSS o JavaScript se pueden servir usando express.js:</p><pre><code class="language-js">var express = require(‘express’);

var app = express();</code></pre><p>y podemos comenzar a escuchar un puerto usando el código:</p><pre><code class="language-js">var servidor = app.listen(3000, () =&gt; {
 console.log(‘el servidor se está ejecutando en el puerto’, servidor.address().port);
});</code></pre><p>Ahora necesitamos crear un archivo HTML index.html que muestre nuestra interfaz de usuario. He agregado bootstrap y JQuery cdn.</p><pre><code class="language-html">//index.html

&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
 &lt;! — incluir bootstrap y jquery cdn →
&lt;/head&gt;
&lt;body&gt;
&lt;div class=”container”&gt;
 &lt;br&gt;
 &lt;div class=”jumbotron”&gt;
 &lt;h1 class=”display-4"&gt;Enviar mensaje&lt;/h1&gt;
 &lt;br&gt;
 &lt;input id = “nombre” class=”form-control” placeholder=”Nombre”&gt;
 &lt;br&gt;
 &lt;textarea id = “mensaje” class=”form-control” placeholder=”Su mensaje aquí”&gt;
&lt;/textarea&gt;
 &lt;br&gt;
 &lt;button id=”enviar” class=”btn btn-success”&gt;Enviar&lt;/button&gt;
 &lt;/div&gt;
 &lt;div id=”mensajes”&gt;
 
&lt;/div&gt;
&lt;/div&gt;
&lt;script&gt;

&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</code></pre><p>Tenga en cuenta que la etiqueta vacía <em><em>&lt;script&gt; &lt;</em></em>;/script&gt; será el lugar en el que escribiremos el código JavaScript del lado del cliente.</p><p>Para decirle a Express eso, usaremos un archivo estático. Agregaremos una nueva línea dentro de <strong>server.js</strong>:</p><pre><code class="language-js">app.use(express.static(__dirname));</code></pre><p>Nosotros podemos ejecutar el server.js usando el comando:</p><pre><code class="language-bash">node ./server.js</code></pre><p>O un paquete llamado <strong>nodemon</strong>, para que los cambios realizados en el código sean detectados automáticamente. Descargaremos nodemon usando el comando:</p><pre><code class="language-bash">npm install -g nodemon</code></pre><p>-g — global, para que sea accesible en todos los proyectos.</p><p>Ejecutaremos el código usando el comando:</p><pre><code class="language-bash">nodemon ./server.js</code></pre><p>Si vas a localhost:3000 podemos ver el archivo de index:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/caxmtV7tYzJ1EUU69TeX4YQVsC69EhgzcSL5" class="kg-image" alt="caxmtV7tYzJ1EUU69TeX4YQVsC69EhgzcSL5" width="800" height="500" loading="lazy"><figcaption>index.html</figcaption></figure><p>Ahora que nuestro servidor está funcionando, necesitamos crear nuestra base de datos. Para esta aplicación, tendremos una base de datos No-SQL y usaremos <strong>Mongodb</strong>. Estoy configurando mi mongodb en <strong><a href="https://www.mongodb.com/es/atlas/database">mongodb.com</a></strong>. Nuestra base de datos contendrá una única colección llamada <strong>mensajes</strong> con los campos <strong>nombre</strong> y <strong>mensaje</strong>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/01/Screenshot-2023-01-23-at-10.02.55-PM.png" class="kg-image" alt="UWJYcDmpxrFhUoKRCrgkhtaTcBD4z4NivreC" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2023/01/Screenshot-2023-01-23-at-10.02.55-PM.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2023/01/Screenshot-2023-01-23-at-10.02.55-PM.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/size/w1600/2023/01/Screenshot-2023-01-23-at-10.02.55-PM.png 1600w, https://www.freecodecamp.org/espanol/news/content/images/2023/01/Screenshot-2023-01-23-at-10.02.55-PM.png 1676w" sizes="(min-width: 720px) 720px" width="1676" height="1122" loading="lazy"></figure><p>Para conectar esta base de datos a la aplicación, usaremos otro paquete llamado <strong>Mongoose</strong>.</p><h4 id="mongoose"><strong><strong><strong>Mongoose</strong></strong></strong></h4><p>Mongoose es una herramienta de modelado de objetos MongoDB diseñada para trabajar en un entorno asíncrono. Mongoose se puede instalar usando el comando:</p><pre><code class="language-bash">npm install -s mongoose</code></pre><p>Dentro de <strong>server.js</strong> necesitaremos mongoose:</p><pre><code class="language-js">var mongoose = require(‘mongoose’);</code></pre><p>Y le asignaremos una variable, la URL de nuestra base de datos mongodb:</p><pre><code class="language-js">var dbUrl = ‘mongodb://username:pass@ds257981.mlab.com:57981/simple-chat’</code></pre><p>Mongoose se conectará a la base de datos mongodb con el método de conexión:</p><pre><code class="language-js">mongoose.connect(dbUrl , (err) =&gt; { 
   console.log(‘Mongodb conectado’,err);
})</code></pre><p>Y definiremos nuestro modelo de mensaje como:</p><pre><code class="language-js">var Mensaje = mongoose.model(‘Mensaje’,{ nombre : String, mensaje: String})</code></pre><p>Podemos implementar la lógica de chat ahora. Pero antes de eso, hay un paquete más que debe agregarse.</p><h4 id="body-parser"><strong><strong><strong>Body-Parser</strong></strong></strong></h4><p>Body-Parser extrae la parte del cuerpo completo de una secuencia de solicitud entrante y la expone en req.body. El middleware formaba parte de Express.js anteriormente, pero ahora debe instalarlo por separado.</p><p>Instálalo usando el siguiente comando:</p><pre><code class="language-bash">npm install -s body-parser</code></pre><p>Agregue los siguientes códigos a <strong>server.js</strong>:</p><pre><code class="language-js">var bodyParser = require(‘body-parser’)
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}))</code></pre><h3 id="enrutamiento"><strong>Enrutamiento</strong></h3><p>El enrutamiento se refiere a cómo los puntos finales de una aplicación (URIs) responden a las solicitudes de los clientes. Usted define el enrutamiento usando métodos del objeto de aplicación Express que corresponden a métodos HTTP: app.get() para manejar solicitudes GET y app.post() para manejar solicitudes POST.</p><p>Estos métodos de enrutamiento especifican <a href="https://expressjs.com/es/guide/routing.html">una función de callback</a> (a veces denominada "funciones de controlador") que se activa cuando la aplicación recibe una solicitud para la ruta (punto final) y el método HTTP especificados. En otras palabras, la aplicación "escucha" las solicitudes que coinciden con las rutas y los métodos especificados, y cuando detecta una coincidencia, llama a la función de callback especificada.</p><p>Ahora necesitamos crear dos rutas a los mensajes para que nuestro chat funcione.</p><p>Dentro de <strong>server.js</strong>:</p><p><strong>get</strong>: obtendrá todos los mensajes de la base de datos</p><pre><code class="language-js">app.get('/mensajes', (req, res) =&gt; {
  Mensaje.find({},(err, mensajes)=&gt; {
    res.send(mensajes);
  })
})</code></pre><p><strong>post </strong>: publicará nuevos mensajes creados por el usuario en la base de datos</p><pre><code class="language-js">app.post('/mensajes', (req, res) =&gt; {
  var mensaje = new Mensaje(req.body);
  mensaje.save((err) =&gt;{
    if(err)
      sendStatus(500);
    res.sendStatus(200);
  })
})</code></pre><p>Para conectar estas rutas al front-end, debemos agregar el siguiente código en la etiqueta del script del lado del cliente en <strong>index.html</strong>:</p><pre><code class="language-js">$(() =&gt; {
    $("#enviar").click(()=&gt;{
       enviarMensaje({
          nombre: $("#nombre").val(), 
          mensaje:$("#mensaje").val()});
        })
      obtenerMensajes()
    })
    
function agregarMensajes(mensaje){
   $(“#mensajes”).append(`
      &lt;h4&gt; ${mensaje.nombre} &lt;/h4&gt;
      &lt;p&gt;  ${mensaje.mensaje} &lt;/p&gt;`)
   }
   
function obtenerMensajes(){
  $.get(‘http://localhost:3000/mensajes', (data) =&gt; {
   data.forEach(agregarMensajes);
   })
 }
 
function enviarMensaje(mensaje){
   $.post(‘http://localhost:3000/mensajes', mensaje)
 }</code></pre><p>Aquí, <strong>enviarMensaje</strong> se usa para invocar la ruta de publicación de los mensajes y guardar un mensaje enviado por el usuario. El mensaje se crea cuando un usuario hace clic en el botón enviar.</p><p>De manera similar, <strong>obtenerMensajes</strong> se usa para invocar la ruta de obtención de mensajes. Esto hará que todos los mensajes se guarden en la base de datos y se agregarán al div de mensajes.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/m1tJ6aV53XnmvkU8PjY7u16wkI1gKrplYWHo" class="kg-image" alt="m1tJ6aV53XnmvkU8PjY7u16wkI1gKrplYWHo" width="800" height="500" loading="lazy"></figure><p>El único problema ahora es que no hay forma de que el cliente sepa si el servidor está actualizado. Entonces, cada vez que publicamos un mensaje, debemos actualizar la página para ver los nuevos mensajes.</p><p>Para solucionar esto podemos añadir un sistema de notificaciones push que enviará mensajes del servidor al cliente. En Node.js usamos <strong>socket.io</strong>.</p><h4 id="socket-io"><strong><strong><strong>Socket.io</strong></strong></strong></h4><p>Socket.IO es una biblioteca de JavaScript para aplicaciones web en tiempo real. Permite la comunicación bidireccional en tiempo real entre los clientes web y el servidor. Tiene dos partes: una biblioteca del lado del cliente que se ejecuta en el navegador y una biblioteca del lado del servidor para Node.js. Socket.io permite la comunicación bidireccional basada en eventos en tiempo real.</p><p>Para instalar socket.io:</p><pre><code class="language-bash">npm install -s socket.io</code></pre><p>también necesitamos un paquete HTTP para que funcione Socket.io:</p><pre><code class="language-bash">npm install -s http</code></pre><p>Agregue el siguiente código a <strong>server.js</strong>:</p><pre><code class="language-js">var http = require(‘http’).Server(app);
var io = require(‘socket.io’)(http);</code></pre><p>Y podemos crear una conexión:</p><pre><code class="language-js">io.on(‘connection’, () =&gt;{
 console.log(‘Un usuario esta conectado’)
})</code></pre><p>En el <strong>index.html</strong> agregue la siguiente etiqueta:</p><pre><code class="language-html">&lt;script src=”/socket.io/socket.io.js”&gt;&lt;/script&gt;</code></pre><p>Ahora necesitamos crear una acción de emisión cuando se crea un mensaje en <strong>server.js</strong>. Así que la ruta de publicación se convierte en esto:</p><pre><code class="language-js">app.post('/mensajes', (req, res) =&gt; {
  var mensaje = new Mensaje(req.body);
  mensaje.save((err) =&gt;{
    if(err)
      sendStatus(500);
    io.emit('mensaje', req.body);
    res.sendStatus(200);
  })
})</code></pre><p>Y en la etiqueta del script del lado del cliente en <strong>index.html</strong>, agregue el siguiente código:</p><pre><code class="language-html">var socket = io();

socket.on(‘mensaje’, agregarMensajes)</code></pre><p>Entonces, cada vez que se publica un mensaje, el servidor actualizará los mensajes en el div de mensajes.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/6KUYtaL4L3ShtPNaHRKWXvP6v3mMuUAdq6R0" class="kg-image" alt="6KUYtaL4L3ShtPNaHRKWXvP6v3mMuUAdq6R0" width="800" height="499" loading="lazy"></figure><p>¡¡Gran!!</p><p>Esta es una aplicación muy básica que podemos crear en Node.js. Hay muchas posibilidades de mejora. El código terminado se puede encontrar en <a href="https://github.com/amkurian/simple-chat" rel="noopener">https://github.com/amkurian/simple-chat</a></p><p><strong><strong>server.js</strong></strong></p><pre><code class="language-js">var express = require('express');
var bodyParser = require('body-parser')
var app = express();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var mongoose = require('mongoose');

app.use(express.static(__dirname));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({extended: false}))

var Mensaje = mongoose.model('Mensaje',{
  nombre : String,
  mensaje : String
})

var dbUrl = 'mongodb://username:password@ds257981.mlab.com:57981/simple-chat'

app.get('/mensajes', (req, res) =&gt; {
  Mensaje.find({},(err, mensajes)=&gt; {
    res.send(mensajes);
  })
})

app.get('/mensajes', (req, res) =&gt; {
  Mensaje.find({},(err, mensajes)=&gt; {
    res.send(mensajes);
  })
})

app.post('/mensajes', (req, res) =&gt; {
  var mensaje = new Mensaje(req.body);
  mensaje.save((err) =&gt;{
    if(err)
      sendStatus(500);
    io.emit('mensaje', req.body);
    res.sendStatus(200);
  })
})

io.on('connection', () =&gt;{
  console.log('Un usuario esta conectado')
})

mongoose.connect(dbUrl ,{useMongoClient : true} ,(err) =&gt; {
  console.log('Mongodb conectado',err);
})

var servidor = http.listen(3001, () =&gt; {
 console.log(‘el servidor se está ejecutando en el puerto’, servidor.address().port);
});</code></pre><p>Espero que esto haya sido útil para comprender algunos conceptos básicos.</p><p>Algunos enlaces útiles</p><p><a href="https://socket.io/" rel="noopener"><strong><strong>Socket.IO</strong></strong></a><br><a href="https://socket.io/" rel="noopener"><em><em>SOCKET.IO 2.0 IS HERE FEATURING THE FASTEST AND MOST RELIABLE REAL-TIME ENGINE ~/Projects/tweets/index.js var io =…</em></em>socket.io</a></p><p><strong><strong><a href="https://expressjs.com/es/">Express - Node.js web application framework</a></strong></strong><br><a href="https://expressjs.com/es/"><em><em>Express is a minimal and flexible Node.js web application framework that provides a robust set of features for web and…</em></em>expressjs.com</a></p><p><a href="http://mongoosejs.com/" rel="noopener">http://mongoosejs.com/</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Git Switch Branch: Cómo cambiar la rama en Git ]]>
                </title>
                <description>
                    <![CDATA[ Cambiar de rama es algo que debes hacer con frecuencia en Git. Para hacer esto, puedes usar el comando git checkout. Cómo crear una nueva rama en Git Para crear una nueva rama en Git, usa el comando git checkout y pasa el indicador -b con un nombre. Esto creará ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/git-switch-branch-como-cambiar-la-rama-en-git/</link>
                <guid isPermaLink="false">62ea9302b4def50851976d2e</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vanessa Pineiro Morales ]]>
                </dc:creator>
                <pubDate>Sat, 06 Aug 2022 03:39:19 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2022/08/60770740776bd507fe31f89c.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/git-switch-branch/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Git Switch Branch – How to Change the Branch in Git</a>
      </p><p>Cambiar de rama es algo que debes hacer con frecuencia en Git.</p><p>Para hacer esto, puedes usar el comando <code>git checkout</code>.</p><h2 id="c-mo-crear-una-nueva-rama-en-git"><strong>Cómo crear una nueva rama en Git</strong></h2><p>Para crear una nueva rama en Git, usa el comando <code>git checkout</code> y pasa el indicador <code>-b</code> con un nombre.</p><p>Esto creará una nueva rama a partir de la rama actual. El historial de la nueva rama comenzará en el lugar actual de la rama de la que "se ramificó".</p><p>Suponiendo que actualmente te encuentras en una rama llamada <code>master</code>:</p><pre><code>(master)$ git checkout -b mi-función
Switched to a new branch 'mi-función'
(mi-función)$</code></pre><p>Aquí puedes ver una nueva rama creada llamada <code>mi-función</code> que se ramificó de <code>master</code>.</p><h2 id="c-mo-cambiar-a-una-rama-existente-en-git"><strong>Cómo cambiar a una rama existente en Git</strong></h2><p>Para cambiar a una rama existente, puedes usar <code>git checkout</code> nuevamente (sin el indicador <code>-b</code> ) y pasar el nombre de la rama a la que desea cambiar:</p><pre><code>(mi-función)$ git checkout master
Switched to branch 'master'
(master)$
</code></pre><p>También hay un atajo útil para volver a la rama anterior en la que estabas, pasando &nbsp;<code>-</code> &nbsp;a &nbsp;<code>git checkout</code> en lugar de un nombre de rama:</p><pre><code>(mi-función)$ git checkout -
Switched to branch 'master'
(master)$ git checkout -
Switched to branch 'mi-función'
(mi-función)$</code></pre><h2 id="c-mo-salir-una-confirmaci-n-espec-fica"><strong>Cómo salir una confirmación específica</strong></h2><p>Para salir o cambiar una confirmación específica, también puedes usar &nbsp;<code>git checkout</code> &nbsp;y pasar el <a href="https://es.wikipedia.org/wiki/Secure_Hash_Algorithm">SHA</a> de la confirmación en lugar de un nombre de rama.</p><p>Después de todo, las ramas en realidad solo son indicadores y rastreadores de confirmaciones específicas en el historial de Git.</p><h3 id="c-mo-encontrar-un-sha-de-una-confirmaci-n"><strong>Cómo encontrar un SHA de una confirmación</strong></h3><p>Una forma de encontrar el SHA de una confirmación es ver el registro de Git.</p><p>Puedes ver el registro usando el comando &nbsp;<code>git log</code>:</p><pre><code>(mi-función)$ git log
commit 94ab1fe28727b7f8b683a0084e00a9ec808d6d39 (HEAD -&gt; mi-función, master)
Author: John Mosesman &lt;johnmosesman@gmail.com&gt;
Date:   Mon Apr 12 10:31:11 2021 -0500

    Este es el segundo mensaje de confirmación.

commit 035a128d2e66eb9fe3032036b3415e60c728f692 (blah)
Author: John Mosesman &lt;johnmosesman@gmail.com&gt;
Date:   Mon Apr 12 10:31:05 2021 -0500

    Este es el primer mensaje de confirmación.
</code></pre><p>En la primera línea de cada confirmación, después de la palabra <code>commit</code>, hay una larga cadena de caracteres y números: <code>94ab1fe28727...</code></p><p>Esto se llama SHA. Un SHA es un identificador único que se genera para cada confirmación.</p><p>Para ver una confirmación específica, solo necesitas pasar el SHA de la confirmación como parámetro para <code>git checkout</code>:</p><pre><code>(mi-función)$ git checkout 035a128d2e66eb9fe3032036b3415e60c728f692
Note: switching to '035a128d2e66eb9fe3032036b3415e60c728f692'.

Estás en estado de 'HEAD separada'. Puedes mirar a tu alrededor,
hacer cambios experimental y confirmaciones, y puede descartar cualquier
confirmación que realices en este estado sin afectar a ninguna rama
cambiando de nuevo a una rama.

Si deseas crear una nueva rama para retener las confirmaciones que creas, puedes
hazlo (ahora o más tarde) usando-c con el comando switch. Ejemplo:

  git switch -c &lt;nombre-de-nueva-rama&gt;

O deshaz esta operación con:

  git switch -

Desactiva este consejo configurando el consejo de la variable de configuración. HEAD separada a falso

HEAD ahora está en 035a128 a
((HEAD separada en 035a128))$
</code></pre><blockquote><strong><strong>Not</strong>a</strong>: Por lo general, solo necesitas usar los primeros caracteres de SHA—ya que los primeros cuatro o cinco caracteres de la cadena probablemente sean únicos en todo el proyecto.</blockquote><h2 id="-qu-es-un-estado-head-separada"><strong>¿Qué es un estado HEAD separada?</strong></h2><p>El resultado de ver una confirmación específica lo coloca en un "estado HEAD separada".</p><p>De la documentación:</p><blockquote>[un estado HEAD separada] significa simplemente que <code>HEAD</code> se refiere a una confirmación específica, en lugar de referirse a una rama nombrada</blockquote><p>Básicamente, <code>HEAD</code> (uno de los indicadores internos de Git que rastrea dónde se encuentra en el historial de Git) se ha desviado de las ramas conocidas, por lo que los cambios desde este punto formarían una nueva ruta en el historial de Git.</p><p>Git quiere asegurarse de que eso es lo que pretendes, por lo que te brinda una especie de "espacio libre" para experimentar, como se describe en el resultado:</p><pre><code>Estás en estado de 'HEAD separada'. Puedes mirar a tu alrededor,
hacer cambios experimental y confirmaciones, y puede descartar cualquier
confirmación que realices en este estado sin afectar a ninguna rama
cambiando de nuevo a una rama.</code></pre><p>Desde esta posición tienes dos opciones:</p><ul><li>Experimenta y luego desecha tus cambios volviendo a tu rama anterior</li><li>Trabaja desde aquí y comienza una nueva rama desde este punto</li></ul><p>Puedes usar el comando <code>git switch -</code> para deshacer cualquier cambio que hayas realizado y volver a tu rama anterior.</p><p>Si, en cambio, deseas mantener tus cambios y continuar desde aquí, puedes usar <code>git switch -c &lt;nueva-rama-nombre&gt;</code> para <em>crear una nueva rama</em> desde este punto.</p><h2 id="conclusi-n"><strong>Conclusión</strong></h2><p>El comando <code>git checkout</code> es un comando útil y multipropósito.</p><p>Puedes usarlo para crear nuevas ramas, ver una rama, ver confirmaciones específicas y más.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Objetos en JavaScript: Una guía para principiantes ]]>
                </title>
                <description>
                    <![CDATA[ Si declaras varios variables para contener diferentes valores, esto puede hacer que su programa se vuelva desordenado y torpe. Por ejemplo, si necesitas almacenar tres características cada una para 10 personas, teniendo 30 variables declaradas individualmente puede hacer que su programa parezca menos organizado. Así que necesitas una forma de ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/objetos-en-javascript-una-guia-para-principiantes/</link>
                <guid isPermaLink="false">62ea4587b4def50851976849</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Vanessa Pineiro Morales ]]>
                </dc:creator>
                <pubDate>Fri, 05 Aug 2022 03:08:03 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2022/08/shelf4.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/objects-in-javascript-for-beginners/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Objects in JavaScript – A Beginner's Guide</a>
      </p><p>Si declaras varios variables para contener diferentes valores, esto puede hacer que su programa se vuelva desordenado y torpe.</p><p>Por ejemplo, si necesitas almacenar tres características cada una para 10 personas, teniendo 30 variables declaradas individualmente puede hacer que su programa parezca menos organizado.</p><p>Así que necesitas una forma de agrupar valores con características similares para que su código sea más legible. Y en JavaScript, los objetos funcionan bien para este propósito.</p><p>A diferencia de otros tipos de datos, los objetos pueden almacenar valores complejos. Debido a esto, JavaScript depende en gran medida de ellos. Así que es importante que se familiarice con lo que es un objeto, cómo crear uno y cómo puede usarlo antes de profundizar el aprendizaje de JavaScript.</p><p>Este artículo le presentará los conceptos básicos de los objetos, la sintaxis de los objetos, los diferentes métodos para crear objetos, cómo copiar objetos y cómo iterar sobre un objeto.</p><p>Para aprovechar al máximo este artículo, debes tener al menos un conocimiento básico de JavaScript, en particular las variables, funciones y tipos de datos.</p><h2 id="-qu-son-los-objetos-en-javascript"><strong>¿Qué son los objetos en JavaScript?</strong></h2><p>Un objeto es un tipo de datos que puede incluir colecciones de pares clave-valor.</p><p>Una diferencia importante entre un objeto y otros tipos de datos, como cadenas y números en JavaScript, es que un objeto puede almacenar diferentes tipos de datos como sus valores. Por otro lado, los tipos de datos primitivos como números y cadenas pueden almacenar solo números y cadenas, respectivamente, como sus valores.</p><p>La clave, también conocida como nombre de propiedad, suele ser una cadena. Si se utiliza cualquier otro tipo de datos como nombre de propiedad que no sean cadenas, se convertirá en una cadena.</p><p>Puede visualizar un objeto como un estante de usos múltiples que contiene espacio para sus dispositivos y adornos, así como un espacio de almacenamiento para libros y archivos.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/07/shelf1-2.jpg" class="kg-image" alt="shelf1-2" width="600" height="400" loading="lazy"><figcaption>Un estante con varios artículos en él.</figcaption></figure><p>La característica más reconocible de un objeto son los corchetes que contienen el par clave-valor.</p><pre><code class="language-javascript">const objetoVacio = {};
console.log(typeof objetoVacio); //'object'</code></pre><p>El contenido de un objeto puede consistir en variables, funciones o ambos. Variables que se encuentran en los objetos son propiedades, mientras que las funciones son métodos. Los métodos permiten que los objetos usen las propiedades dentro de ellos para realizar algún tipo de acción.</p><p>Por ejemplo, en el código de muestra a continuación, <strong>objeto1.usuario</strong>, <strong>objeto1.nacionalidad</strong> y <strong>objeto1.profesion</strong> son propiedades de <strong>objeto1</strong> mientras que <strong>objeto1.miBiografia()</strong> es un método:</p><pre><code class="language-javascript">const objeto1 = {
  usuario: "Alex",
  nacionalidad: "Nigeria",
  profesion: "Ingeniero de Software",
  miBiografia() {
    console.log(
      `Mi nombre es ${this.usuario}. Soy un ${this.profesion} de ${this.nacionalidad}`
    );
  },
};
console.log(objeto1.usuario); // Alex
console.log(objeto1.nacionalidad); // Nigeria
console.log(objeto1.profesion); // Ingeniero de Software
console.log(objeto1.miBiografia()); // Mi nombre es Alex. Soy un Ingeniero de Software de Nigeria</code></pre><p>Las claves en el código de muestra anterior son<strong> usuario</strong>,<strong> nacionalidad</strong> y <strong>profesion</strong>, mientras que sus valores son los valores de cadena que vienen después de los dos puntos. Además, observa el uso de la palabra clave <strong>this</strong>. La palabra clave <strong>this</strong> simplemente se refiere al objeto en sí.</p><p>Como se mencionó anteriormente en este artículo, el valor de una propiedad puede ser cualquier tipo de datos. En el siguiente código de ejemplo, los valores son <br>arreglos y objetos:</p><pre><code class="language-javascript"> const objeto2 = {
  usuario: ["Alex", "James", "Mohammed"],
  profesión: {
    alex: "Ingeniero de Software",
    james: "Abogado",
    mohammed: "Escritor técnico",
  },
};
console.log(objeto2.usuario); // ['Alex', 'James', 'Mohammed']
console.log(objeto2.profesión); // {alex: "Ingeniero de Software", james: "Abogado", mohammed: "Escritor técnico"}</code></pre><h2 id="c-mo-acceder-a-objetos-y-crear-nuevas-propiedades-o-m-todos-de-objeto-en-javascript"><strong>Cómo acceder a objetos y crear nuevas propiedades o métodos de objeto en JavaScript</strong></h2><p>Hay dos formas de acceder a los objetos: notación de puntos y notación de corchetes. En el código de muestra anterior, usamos la notación de puntos para acceder a las propiedades y métodos en el<strong> objeto1</strong> y el <strong>objeto2</strong>.</p><p>Además, para crear nuevas propiedades y métodos después de la declaración de un objeto, puedes usar la notación de puntos o la notación de corchetes. Solo tienes que indicar la nueva propiedad y darle un valor.</p><p>Por ejemplo, podemos agregar nuevas propiedades a <strong>objeto2 </strong>de este modo:</p><pre><code class="language-javascript">objeto2.edad = [30, 32, 40];
objeto2["resumen"] = `Objeto2 tiene ${objeto2.usuario.length} usuarios`;
console.log(objeto2);
/*
{
    "usuario": [
        "Alex",
        "James",
        "Mohammed"
    ],
    "profesion": {
        "alex": "Ingeniero de Software",
        "james": "Abogado",
        "mohammed": "Escritor técnico"
    },
    "edad": [
        30,
        32,
        40
    ],
    "resumen": "Objeto2 tiene 3 usuarios"
}
*/</code></pre><p>De manera similar, puedes usar cualquier notación para cambiar el valor de un objeto:</p><pre><code class="language-javascript">objeto2.usuario = ["jane", "Williams", "John"];
objeto2["edad"] = [20, 25, 29];
console.log(objeto2.usuario); //['jane', 'Williams', 'John']
console.log(objeto2.edad); //[20, 25, 29]</code></pre><p>Aunque la notación de puntos es la más utilizada para acceder a las propiedades y métodos de un objeto, tiene algunas limitaciones. Veámoslos ahora.</p><h2 id="no-puedes-usar-valores-como-nombres-de-propiedades-con-notaci-n-de-puntos"><strong>No puedes usar valores como nombres de propiedades con notación de puntos</strong></h2><p>Si deseas utilizar el valor de un variable como nombre de propiedad en su objeto, debes utilizar la notación de corchetes y no la notación de puntos. Si el valor de el variable se define en tiempo de ejecución o no es irrelevante.</p><p>El tiempo de ejecución es una fase de un programa de computadora en la que el programa se ejecuta en un sistema de computación.</p><p>Por ejemplo:</p><pre><code class="language-javascript">const objeto3 = {};
const aparato = prompt("ingresa un tipo de aparato");
objeto3[aparato] = ["jbl", "sony"];
console.log(objeto3); // (respuesta ingresada en el prompt): ["jbl","sony"] observa que el nombre de la propiedad es el valor que ingresa en la respuesta al mensaje del prompt</code></pre><p>Si defines el valor de el variable en su código, y usas la notación de puntos para establecer ese valor como un nombre de propiedad de su objeto, la notación de puntos creará una nueva propiedad con el nombre de el variable en lugar del valor de el variable.</p><pre><code class="language-javascript">const computadora = "marcas";
objeto3.computadora = ["hp", "dell", "apple"];
console.log(objeto3.marcas); // undefined
console.log(objeto3.computadora); // ['hp', 'dell', 'apple']

objeto3[computadora] = ["hp", "dell", "apple"];
console.log(objeto3.marcas); // ['hp', 'dell', 'apple']</code></pre><p>Nota la omisión de comillas dentro de los corchetes. Esto se debe a que los paréntesis tomaron un variable.</p><h3 id="no-puedes-usar-propiedades-de-varias-palabras-con-notaci-n-de-puntos"><strong>No puedes usar propiedades de varias palabras con notación de puntos</strong></h3><p>Cuando el nombre de la propiedad es una cadena de varias palabras, la notación de puntos es insuficiente. Por ejemplo:</p><pre><code class="language-javascript">objeto3.usuario altura = [5.6, 5.4, 6.0];
Console.log(objeto3.usuario altura); //SyntaxError
</code></pre><p>Se produce un error de sintaxis porque JavaScript lee el comando como &nbsp;<code>objeto3.usuario</code>, pero no reconoce la altura de la cadena, entonces devuelve un error de sintaxis.</p><p>Cuando se utiliza la notación de puntos para acceder a objetos, se aplican las reglas habituales de declaración de un variable. Esto significa que si deseas utilizar la notación de puntos para acceder a un objeto o crear una propiedad, el nombre de la propiedad no debe comenzar con un número, no debe incluir espacios y solo puede incluir los caracteres especiales <em>$</em> y _.</p><p>Para evitar este tipo de error, debes usar la notación de corchetes. Por ejemplo, puedes corregir el código de muestra anterior de esta manera:</p><pre><code class="language-javascript">objeto3["usuario altura"] = [5.6, 5.4, 6.0];  
console.log(objeto3["usuario altura"]); //[5.6, 5.4, 6]</code></pre><h2 id="c-mo-crear-objetos-con-el-constructor-de-objetos-en-javascript"><strong>Cómo crear objetos con el constructor de objetos en JavaScript</strong></h2><p>Hay dos métodos por cuál puedes crear un objeto: un objeto literal y el constructor de objetos. Los objetos usados hasta ahora como ejemplos en este artículo son objetos literales. Objetos literales funcionan bien si deseas crear un solo objeto.</p><p>Pero si deseas crear más de un objeto, siempre es mejor usar el constructor de objetos. Esto le permite evitar repeticiones innecesarias en su código y también facilita cambiar las propiedades de su objeto.</p><p>Básicamente, los constructores son funciones cuyos nombres suelen estar en mayúsculas. El uso de mayúsculas en el nombre de un constructor no tiene ningún efecto en el objeto. Es sólo un medio de identificación.</p><p>Puedes usar un constructor para crear un nuevo objeto llamando al constructor con la palabra clave <strong>new</strong>. La palabra clave <strong>new</strong> creará una instancia de un objeto y vinculará la palabra clave <strong>this</strong> al nuevo objeto.</p><p>Como se mencionó anteriormente en este artículo, la palabra clave <strong>this</strong> es una referencia al objeto en sí.</p><p>Un ejemplo de un constructor de objetos es:</p><pre><code class="language-javascript">function Perfil(nombre, edad, nacionalidad) {
  this.nombre = nombre;
  this.edad = edad;
  this.nacionalidad = nacionalidad;
  this.biografia = function () {
    console.log(
      `Mi nombre es ${this.nombre}. Tengo ${this.edad} años de edad. Soy de ${this.nacionalidad}.`
    );
  };
}

const oladele = new Perfil("Oladele", 50, "Nigeria");
console.log(oladele.biografia()); // Mi nombre es Oladele. Tengo 50 años de edad. soy de Nigeria.</code></pre><h2 id="c-mo-crear-copias-de-objetos-en-javascript"><strong>Cómo crear copias de objetos en JavaScript</strong></h2><p>A diferencia de los tipos de datos primitivos, como cadenas y números, la asignación de un objeto existente a otro variable no producirá una copia del original sino una referencia en la memoria.</p><p>Lo que esto significa es que tanto el objeto original como los objetos posteriores creados al asignar el objeto original como un valor hacen referencia al mismo elemento en la memoria.</p><p>Esto significa que un cambio en el valor de cualquiera de los objetos también provocará un cambio en los demás. Por ejemplo:</p><pre><code class="language-javascript">let x = 10;
let y = x;
x = 20;
console.log(x); // 20
console.log(y); // 10

let objeto4 = {
  nombre: "Alex",
  edad: 40,
};
let objeto5 = objeto4;
console.log(objeto5); // {nombre: 'Alex', edad: 40}
objeto4.nombre = "Jane";
console.log(objeto5); // {nombre: 'Jane', edad: 40}
console.log(objeto4 === objeto5); // true</code></pre><p>Para crear una copia de un objeto, puedes utilizar el operador de propagación.</p><h3 id="-qu-es-el-operador-de-propagaci-n"><strong>¿Qué es el operador de propagación?</strong></h3><p>El operador de propagación está representado por tres puntos <code>...</code> . Puedes utilizar el operador de propagación para copiar los valores de cualquier iterable incluyendo objetos.</p><p>Un iterable es un objeto que se puede repetir o iterar con la ayuda de un for...bucle. Los ejemplos de iterables incluyen objetos, arreglos, conjuntos, cadenas, etc.</p><p>Para usar el operador de propagación, debes anteponerlo al objeto del que deseas copiar. Por ejemplo:</p><pre><code class="language-javascript">let objeto6 = {...objeto5}; 
objeto5.nombre = "Willaims"; 
console.log(objeto5); //{nombre: 'Willaims', edad: 40}
console.log(objeto6); //{nombre: 'Jane', edad: 40}
console.log(objeto5 === objeto6); //false</code></pre><p>Como puedes ver, a diferencia del ejemplo de código anterior, donde un cambio en el <strong>objeto4</strong> causó un cambio en el <strong>objeto5</strong>, el cambio en el <strong>objeto6</strong> no resultó en un cambio en el <strong>objeto5</strong>.</p><h3 id="c-mo-utilizar-el-m-todo-object-assign-"><strong>Cómo utilizar el método Object.assign()</strong></h3><p>El método <strong>Object.assign()</strong> copia todas las propiedades enumerables de un objeto en otro y luego devuelve el objeto modificado.</p><p>El método toma dos parámetros. El primer parámetro es el objeto de destino que toma las propiedades copiadas. El segundo parámetro es el objeto de origen que tiene las propiedades que desea copiar. Por ejemplo :</p><pre><code class="language-javascript">let objeto7  = Object.assign({}, objeto6); 
console.log(objeto7); //{nombre: 'Jane', edad: 40}
console.log(objeto7); //{nombre: 'Jane', edad: 40}

console.log(objeto6 === objeto7); //false
objeto6.edad = 60
console.log(objeto6); //{nombre: 'Jane', edad: 60}
console.log(objeto7); //{nombre: 'Jane', edad: 40}</code></pre><p>Puedes ver en el código de ejemplo anterior que un cambio en el valor de la propiedad de <strong>edad</strong> del <strong>objeto6</strong> no provocó un cambio en el valor de la propiedad de <strong>edad</strong> del <strong>objeto7</strong>.</p><p>Ten en cuenta que tanto el operador de propagación como el método <strong>Object.assign()</strong> solo pueden hacer una copia superficial de un objeto.</p><p>Esto significa que si tienes objetos o arreglos profundamente anidados en tu objeto de origen, solo las referencias a dichos objetos se copian en el objeto de destino. Entonces, un cambio en el valor de cualquiera de los objetos profundamente anidados provocaría un cambio en el valor del objeto profundamente anidado del otro. Por ejemplo:</p><pre><code class="language-javascript">let objetoX = {
  nombre: "Mary",
  edad: 40,
  aparato: {
    marca: ["apple", "sony"],
  },
};

let objetoY = { ...objetoX };
objetoY.nombre = "Bianca";
objetoY.aparato.marca[0] = "hp";
console.log(objetoX);
/*
{
    "nombre": "Mary",
    "edad": 40,
    "aparato": {
        "marca": [
            "hp",
            "sony"
        ]
    }
}
*/

console.log(objetoY);
/*
{
    "nombre": "Bianca",
    "edad": 40,
    "aparato": {
        "marca": [
            "hp",
            "sony"
        ]
    }
}
*/</code></pre><p>El código de muestra anterior realizó las siguientes acciones:</p><ol><li>Creó un objeto llamado <strong><strong>objet</strong>o<strong>X</strong></strong>.</li><li>Le dio tres propiedades al <strong>objetoX</strong>: nombre, edad y aparato.</li><li>Le dio a la propiedad de <strong>aparato</strong> del <strong>objetoX</strong> un objeto como su valor.</li><li>Le dio al valor de objeto de la propiedad de <strong>aparato</strong> una propiedad de <strong>marca</strong>.</li><li>Le dio a la propiedad de <strong>marca</strong> un arreglo como su valor.</li><li>Copio las propiedades del <strong>objetoX</strong> en el <strong>objetoY</strong> con el uso del operador de propagación.</li><li>Cambió el valor de la propiedad de <strong>nombre </strong>del <strong>objetoY</strong> a <strong>Mary</strong>.</li><li>Cambió el primer elemento en el valor de el arreglo de la propiedad de la <strong>marca</strong> de <strong>apple</strong> a <strong>hp</strong>.</li></ol><p>En el código de muestra, el valor de el arreglo es un objeto profundamente anidado. Observa que un cambio en el valor de la propiedad de <strong>nombre</strong> del <strong>objetoY</strong> no provocó un cambio en el valor de la propiedad de <strong>nombre</strong> del <strong>objetoX</strong>. Pero un cambio en el objeto profundamente anidado del <strong>objetoY</strong> provocó un cambio similar en el objeto profundamente anidado del <strong>objetoX</strong>.</p><h2 id="c-mo-iterar-sobre-objetos-en-javascript"><strong>Cómo Iterar Sobre Objetos en JavaScript</strong></h2><p>Use un bucle <strong>for...in</strong> para iterar sobre un objeto y seleccionar sus propiedades. La sintaxis del bucle <strong>for..in</strong> es la siguiente:</p><pre><code class="language-javascript">for(let llave in objeto) {
    //realizar acción(es) para cada llave
}</code></pre><p>La palabra clave <strong>llave</strong> en el sintaxis anterior es un parámetro para las propiedades. Así que puedes reemplazarlo con cualquier palabra de tu elección. Reemplace la palabra clave del objeto con el nombre del objeto sobre el que desea iterar. Por ejemplo:</p><pre><code class="language-javascript">let objetoZ = {
  nombre: "Ade",
  Pronombre: "el",
  edad: 60,
};
for (let propiedad in objetoZ) {
  console.log(`${propiedad}: ${objetoZ[propiedad]}`);
}
/* 
nombre: Ade
Pronombre: he
edad: 60
*/</code></pre><p>Observa el uso de la notación de corchetes en el bucle para obtener los valores de la propiedad. El uso de la notación de puntos en lugar de la notación de corchetes devolvería undefined.</p><h2 id="conclusi-n"><strong>Conclusión</strong></h2><p>En JavaScript, los objetos son probablemente el tipo de datos más importante. Los conceptos de programación como la programación orientada-a-objetos funcionan según el principio de aprovechar la flexibilidad de los objetos para almacenar valores complejos y su capacidad distintiva de interactuar con propiedades y métodos dentro del objeto.</p><p>Este artículo establece una base sólida para comprender conceptos tan avanzados al explicar los conceptos básicos de los objetos.</p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
