<?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[ Israel Palma - 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[ Israel Palma - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/espanol/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 19:37:22 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/espanol/news/author/israel/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Señales en Angular - Cómo escribir código reactivo ]]>
                </title>
                <description>
                    <![CDATA[ ¡Una nueva y emocionante característica llega a Angular! Las señales, estas proveen una nueva forma de comunicación de nuestro código que comunique a nuestras plantillas que los datos han cambiado. Esto mejora la capacidad de detección de cambios de Angular, lo que también mejora el rendimiento y hace nuestro código ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/senales-en-angular-como-escribir-codigo-reactivo/</link>
                <guid isPermaLink="false">667384c4b6f94103d5aef8e9</guid>
                
                    <category>
                        <![CDATA[ angular ]]>
                    </category>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Palma ]]>
                </dc:creator>
                <pubDate>Fri, 08 Nov 2024 02:51:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/06/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/angular-signals/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Signals in Angular – How to Write More Reactive Code</a>
      </p><p>¡Una nueva y emocionante característica llega a Angular! Las señales, estas proveen una nueva forma de comunicación de nuestro código que comunique a nuestras plantillas que los datos han cambiado. Esto mejora la capacidad de detección de cambios de Angular, lo que también mejora el rendimiento y hace nuestro código más reactivo.</p><p>Ya puedes probar las señales, están disponibles con acceso anticipado para desarrolladores (developer preview) en Angular v16, que se publicará en mayo de 2023. Te muestro como hacerlo más adelante.</p><p>Si gustas puedes ver el vídeo asociado (en inglés):</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.17977528089888%;" class="fluid-width-video-wrapper">
            <iframe width="356" height="200" src="https://www.youtube.com/embed/oqYQG7QMdzw?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Angular Signals: What? Why? and How?" name="fitvid0" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 22px; vertical-align: middle; position: absolute; top: 0px; left: 0px; width: 720px; height: 404.489px;"></iframe>
          </div>
        </div>
      </figure><p>Encuentra el código de este tutorial aquí: <a href="https://stackblitz.com/edit/angular-signals-deborahk">https://stackblitz.com/edit/angular-signals-deborahk</a>.</p><p>Antes de adentrarnos en detalles del "qué" y el "cómo", vamos a empezar con el "por qué". Entonces, ¿por qué usar las señales?</p><h2 id="-por-qu-necesitamos-las-se-ales"><strong>¿Por qué necesitamos las señales?</strong></h2><p>Empecemos con un ejemplo simple que no utiliza señales. Digamos que estás escribiendo código para realizar algunas operaciones matemáticas.</p><pre><code class="language-typescript">let x = 5;
let y = 3;
let z = x + y;
console.log(z);//~8</code></pre><p>¿Qué es lo que este código imprime por consola? Así es, imprime <code>8</code>.</p><p>En alguna parte más adelante en el código cambiamos el valor de <code>x</code>. ¿Qué valor de <code>z</code> se imprime por consola ahora?</p><pre><code class="language-typescript">let x = 5;
let y = 3;
let z = x + y;
console.log(z);

x = 10;
console.log(z);//~8</code></pre><p>¡Aún imprime <code>8</code>! Esto se debe a que el valor se asigna a <code>z</code> desde el inicio cuando la expresión se ha evaluado. La variable <code>z</code> no reacciona a los cambios en <code>x</code> o en <code>y</code>.</p><p>¡Pero queremos que nuestras variables reaccionen a los cambios! </p><p>Una de las razones por las que usamos Angular es para crear sitios web interactivos y reactivos, es decir, con capacidad de reaccionar a los cambios de los datos. </p><p>Como por ejemplo en la Figura 1. Cuando el usuario edita la cantidad, las variables relacionadas, como el total, sub-total e impuestos, deberían reaccionar y ajustar los costos automáticamente. Si el usuario decide borrar un item del carrito también queremos que las variables relacionadas sean capaces de re-calcular los costos.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/07/Cantidad.jpg" class="kg-image" alt="b3SbnD_bufoicCX2VGyQiA624LQEC7yIEAVeEj0aVHjxvwmNnTPs-qE565koSuPWUrjAj-UDSw9otj6fXRWHPtr9jce2fnLt8FFAiLP0KRijjpuUiN_cb9lFwe_IbmsSWSzWqV36zBa8Bsnh7ciX4zo" srcset="https://www.freecodecamp.org/espanol/news/content/images/2024/07/Cantidad.jpg 600w" width="600" height="253" loading="lazy"><figcaption>Figura 1. El carrito reacciona y re-calcula los precios cuando el usuario modifica la cantidad.</figcaption></figure><p>Con las señales nuestro código puede ser más reactivo. En nuestro anterior ejemplo la implementación de señales se vería así:</p><pre><code class="language-typescript">const x = signal(5);
const y = signal(3);
const z = computed(() =&gt; x() + y());
console.log(z()); // 8

x.set(10);
console.log(z()); // 13</code></pre><p>Veremos la sintaxis y lo demostraremos a detalle más adelante. Por ahora, el código de arriba define dos señales: <code>x</code> y <code>y</code> además de darles valores iniciales de <code>5</code> y <code>3</code>. Entonces definimos una señal computada <code>z</code>, que es la suma de <code>x</code> y <code>y</code>. Debido a que las señales proveen notificaciones de cambios cuando cambian los valores de las señales <code>x</code> o <code>y</code>, cualquier valor computado a partir de esas señales se re-calculará automáticamente. ¡Este código es reactivo! ¡Excelente!</p><p>Las señales computadas reaccionan y se re-calculan cuando cualquiera de sus señales dependientes cambia. Si una señal está vinculada en una plantilla de Angular, al cambiar dicha señal, el mecanismo de detección de cambios de Angular actualiza cualquier vista que pueda leer la señal. Y los usuarios visualizan los valores modificados.</p><p>Por lo que es posible dar respuesta a la pregunta de, ¿por qué necesitamos las señales? De la siguiente manera:</p><ul><li>Las señales permiten la reactividad.</li><li>Usando señales podemos tener mayor control en la detección de cambios, lo cual puede mejorar el desempeño.</li></ul><p>Profundicemos un poco más para entender lo que es una señal y cómo se usa.</p><h2 id="-qu-es-una-se-al"><strong>¿Qué es una señal?</strong></h2><p>Podemos pensar de una señal como un valor que además tiene la capacidad de notificar cambios. Una señal es un tipo especial de variable que almacena un valor. Pero a diferencia de otras variables, una señal también provee notificaciones cuando el valor de la variable cambia.</p><p>Imagínate una variable normal como si fuera un estante o repisa, como en el lado izquierdo de la figura 2. Cuando un valor se asigna a la variable, ésta se colocaría en el estante. Cualquier código dentro del alcance puede simplemente ver (leer) la variable en el estante.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://lh6.googleusercontent.com/VNW2DY2fkiBRNox5DIGkh2qr_yRgurq7I3vLumHSqT2ACNKq6I3GiGcMpVvU6f2AImTNIJ3quMh7lzerxfRjD3WBiLPEKBWGRgxGfvsrWpwuvBpvbpllPKJ-lZWHzQLRBguqAHWnITJU3xajiV2BoZM" class="kg-image" alt="VNW2DY2fkiBRNox5DIGkh2qr_yRgurq7I3vLumHSqT2ACNKq6I3GiGcMpVvU6f2AImTNIJ3quMh7lzerxfRjD3WBiLPEKBWGRgxGfvsrWpwuvBpvbpllPKJ-lZWHzQLRBguqAHWnITJU3xajiV2BoZM" width="600" height="400" loading="lazy"><figcaption>Figura 2. Metafóricamente, una variable normal está en un estante. Una señal se almacena en una caja que brilla cuando cambia.</figcaption></figure><p>Una señal tiene mayor parecido a una caja, como se muestra al lado derecho de la figura 2. Al crear una señal, creamos algo análogo a una caja y el valor se coloca dentro de ésta. Cuando el valor que se encuentra dentro cambia, la caja emite un brillo para avisarle. Para leer la señal, es decir el valor almacenado, primero debemos abrir "la caja" usando paréntesis: <code>x()</code>. Técnicamente llamamos a la función "getter" (literal de conseguidor, método o función que devuelve un valor) de la señal para leer el valor de esta.</p><p>Ahora pues, ya sabemos que es una señal.</p><ul><li>Una señal es una variable con notificaciones de cambios.</li><li>Es un valor reactivo o bien un "reactivo primitivo".</li><li>Siempre tiene un valor</li><li>Es síncrona.</li><li>No es un sustituto o remplazo de RxJS ni de Observables para operaciones asíncronas como <code>http.get</code>.</li></ul><p>¿Dónde podemos usarlas?</p><ul><li>En <strong>componentes</strong> para monitorear su estado local. </li><li>En <strong>directivas</strong>.</li><li>En <strong>servicios </strong>para compartir el estado entre componentes.</li><li>Para su lectura en una <strong>plantilla</strong> (del inglés template) para mostrar lo valores.</li><li>O en cualquier otra parte de tu código.</li></ul><p>A continuación, vayamos paso a paso viendo cómo crear y usar señales.</p><h2 id="c-mo-crear-una-se-al"><strong>Cómo crear una señal</strong></h2><p>Para usar una señal tenemos primero, por supuesto, que crearla. </p><pre><code class="language-typescript">cantidad = signal&lt;number&gt;(1);</code></pre><p>Esta es la sintaxis para escribir el código para crear e inicializar una señal usando el método constructor <code>signal()</code>. </p><p>De forma opcional como podemos ver, es posible pasar un parámetro genérico para definir el tipo de dato de la señal. Una señal puede ser de tipo string, number, array, object o cualquier tipo de dato. En muchos casos el tipo de dato puede inferirse y por lo tanto no es necesario u obligatorio pasar el parámetro de tipo genérico. </p><p>Pasemos al constructor el valor por defecto para nuestra señal, ya que una señal siempre debe tener un valor, y por lo tanto, es necesario inicializarlas con un valor por defecto.</p><p>Aquí te muestro algunos otros ejemplos:</p><pre><code class="language-typescript">cantidad = signal(1);

cantidadDisponible = signal([1, 2, 3, 4, 5, 6]);

vehiculoSeleccionado = signal&lt;Vehiculo&gt;({ 
  id: 1,
  nombre: 'AT-AT', 
  precio: 19416.13
});

vehiculos = signal&lt;Vehiculo[]&gt;([]);</code></pre><p>La primera línea de este código crea una señal numérica con un valor por defecto (predefinido) de <code>1</code>. Ya que el valor predeterminado es de tipo <code>number</code>, la <code>cantidad</code> es una señal que contiene un número. El parámetro del tipo genérico no se necesita pasar, ya que como vimos el tipo del dato es inferido automáticamente.</p><p>La segunda línea es una señal que contiene un arreglo de números, donde su valor predefinido corresponde con los valores del 1 al 6. De nuevo, no necesitamos pasar el parámetro de tipo genérico ya que el tipo de dato se infiere automáticamente a partir del tipo de dato del valor que hemos pasado.</p><p>La señal <code>vehiculoSeleccionado</code> contiene un objeto de tipo <code>Vehiculo</code>. En este ejemplo el tipo no puede inferirse, por lo que especificamos un parámetro de tipo genérico para <code>Vehiculo</code>. </p><p>La señal <code>vehiculos</code> contiene un arreglo para objetos de tipo <code>Vehiculo</code>, que está vacío por defecto. Para que este arreglo posea tipos estático y pueda recibir elementos del tipo de dato <code>Vehiculo</code>, agregamos el parámetro genérico de tipo de datos <code>&lt;Vehiculo[]&gt;</code>. &nbsp; </p><p>Una señal que fue creada utilizando el constructor es editable, por lo que puedes asignarle un valor nuevo o diferente, actualizarla en base a su valor actual o mutar su contenido. En breve veremos ejemplos de cómo realizar estas operaciones.</p><p>Una vez que hayas creado una señal es posible que quieras leer su valor.</p><h2 id="c-mo-leer-una-se-al"><strong>Cómo leer una señal</strong></h2><p>Anteriormente planteamos pensar que una señal es una caja. Hablando metafóricamente podemos decir que para leer el valor de una señal es necesario primero abrir la caja. Ya que las señales son funciones, esto lo hacemos invocando la señal con el uso de paréntesis.</p><pre><code class="language-typescript">quantity();</code></pre><p>Empecemos con el nombre de la señal y enseguida con el paréntesis de apertura y luego el de cierre. Técnicamente esto a su vez invoca a la función "getter", la cual es creada "por debajo", por lo que no es visible en el código.</p><p>Cuando se trabaja con Angular es común leer las señales en el "template" (plantilla).</p><pre><code class="language-html">&lt;select
    [ngModel]="cantidad()"
    (change)="alSeleccionarCantidad($any($event.target).value)"&gt;
  &lt;option *ngFor="let c of cantidadDisponible()"&gt;{{ c }}&lt;/option&gt;
&lt;/select&gt;

&lt;div&gt;Vehículo: {{ vehiculoSeleccionado().nombre }}&lt;/div&gt;
&lt;div&gt;Price: {{ vehiculoSeleccionado().precio }}&lt;/div&gt;
&lt;div [style.color]="color()"&gt;Total: {{ precioTotal() }}&lt;/div&gt;</code></pre><p>La plantilla de arriba muestra una caja de selección de cantidad. La directiva <code>[ngModel]</code> lee el valor de la señal <code>cantidad</code> y crea un enlace o "binding" a ese valor.</p><p>El enlace o "binding" al evento <code>change</code> invoca el método <code>alSeleccionarCantidad()</code> del componente.</p><p>El elemento html <code>option</code> usa la directiva <code>ngFor</code> para iterar por cada elemento del arreglo en la señal <code>cantidadDisponible</code>. Lee la señal y crea una opción en el <code>select</code> para cada elemento del arreglo.</p><p>Debajo del elemento <code>select</code> encontrarás tres elementos <code>div</code>, el primero lee la señal <code>vehiculoSeleccionado</code>, luego accede a su propiedad <code>nombre</code>. El segundo elemento <code>div</code> lee la señal <code>vehiculoSeleccionado</code> y muestra su propiedad <code>precio</code>. El último <code>div</code> lee la señal <code>precioTotal</code> (que no hemos definido aún), y utiliza el valor de la señal <code>color</code> (que tampoco hemos definido todavía) para determinar el color del texto.</p><p>Es importante nota que al leer una señal siempre obtendremos el valor actual, y el código no tiene conocimiento de ningún valor previo.</p><p>Cuando el usuario elige una cantidad diferente en el elemento <code>select</code> queremos cambiar el valor de la señal <code>cantidad</code>. De esa manera la señal <code>cantidad</code> se transforma en la "fuente de verdad" para la cantidad seleccionada por el usuario. Veamos cómo hacerlo a continuación.</p><h2 id="c-mo-cambiar-el-valor-de-una-se-al"><strong>Cómo cambiar el valor de una señal</strong></h2><p>El método <code>set</code> reemplaza el valor de una señal con un nuevo valor. Básicamente "abre la caja", quita el ítem actual y asigna un nuevo ítem que tomará el lugar del anterior.</p><pre><code class="language-typescript">this.cantidad.set(cant);</code></pre><p>Una situación común es cambiar el valor de la señal en base a una acción del usuario. Por ejemplo:</p><ul><li>El usuario selecciona una nueva cantidad usando el elemento <code>select</code>.</li><li>El evento ligado al elemento <code>select</code> invoca al método <code>alSeleccionarCantidad()</code> y pasa la cantidad seleccionada por el usuario.</li><li>La acción del usuario se maneja en el componente usando la función o método definido para este propósito. </li><li>El nuevo valor se asigna a la señal <code>cantidad</code>.</li></ul><p>Este es un ejemplo de una función para el manejo de eventos (event handler):</p><pre><code class="language-typescript">alSeleccionarCantidad(cant: number) {
  this.cantidad.set(cant);
}</code></pre><p>En el momento en que se haya asignado o re-asignado la señal, el código notifica a cualquier consumidor de la señal que esta ha cambiado. En este contexto, un consumidor es cualquier código que tenga interés en recibir notificaciones de cambios del valor de la señal. </p><p>¿Cómo es que el consumidor indica que tiene interés en ser notificado de los cambios de una señal en particular?</p><p>Si <strong>un código lee una señal</strong>, ese código será notificado cuando la señal cambie.</p><p>Si <strong>una plantilla lee una señal</strong>, será notificada cuando la señal cambie y la "vista" (view) sea programada para volver a renderizarse.</p><p>Por lo que el acto de leer una señal registra el interés del consumidor de observar el valor y los cambios de dicha señal. El equipo de Angular le llama a esto la <strong>regla de oro</strong> de las señales en componentes: "la detección de cambios en un componente se agendará cuando y sólo cuando la lectura de una señal en el plantilla notifique a Angular que su valor a cambiado".</p><p>Aquí un ejemplo para ilustrar el proceso. Digamos que hay algo de trabajo realizándose dentro del método (mostrado abajo) que busca ajustar la cantidad. Digamos que quizá el caso de uso podría ser algo como una promoción, que si por ejemplo el usuario elige una cantidad igual o mayor a 5 entonces se lleva uno gratis. El punto es que la señal <code>cantidad</code> podría cambiar en varias ocasiones durante la ejecución del método.</p><pre><code class="language-typescript">alSeleccionarCantidad(cant: number) {
  this.cantidad.set(qty);
  
  this.cantidad.set(5);
  this.cantidad.set(42);
}</code></pre><p>La cantidad se muestra en la plantilla usando la vinculación de Angular (binding) como se muestra abajo. Ya que el vínculo "lee" la señal <code>cantidad</code>, la plantilla "registra" su interés en recibir notificaciones de cambios. </p><pre><code class="language-html">//Angular binding (vinculación en la plantilla)
{{ cantidad() }}</code></pre><p>Cuando el usuario elige la cantidad el método <code>alSeleccionarCantidad()</code> se ejecuta. El código en este método primero asigna el valor seleccionado por el usuario a la señal <code>cantidad</code>. Luego cuando la nueva señal se asigna esta genera una notificación. En este punto, se agenda la ejecución del mecanismo de detección de cambios de Angular, pero no tiene la oportunidad de hacerlo sino hasta después de la ejecución del método <code>alSeleccionarCantidad()</code>. &nbsp; </p><p>Entonces, el método <code>alSeleccionarCantidad()</code> continúa asignando el número <code>5</code> a la señal, que genera otra notificación de cambio. De nuevo el mecanismo de detección de cambios de Angular es llamado a ejecutarse pero aún debe esperar a que el método <code>alSeleccionarCantidad()</code> termine su ejecución. El método entonces asigna el valor <code>42</code> a la señal y el proceso se repite.</p><p>Cuando se completa la ejecución del método <code>alSeleccionarCantidad()</code> finalmente será turno de ejecución del mecanismo de detección de cambios de Angular. La plantilla lee la señal y obtiene su valor, que es <code>42</code>. La plantilla no es "consciente" de ninguno de los valores anteriores. La vista se vuelve a "renderizar" y el nuevo valor de la señal <code>cantidad</code> se mostrará. </p><p>Si la señal cambia, cualquier "consumidor" interesado en su lectura será notificado. Pero el consumidor no recibirá el nuevo valor, sino que, hasta la próxima vez, cuando sea el turno de ejecución del consumidor es entonces que podrá "leer" el valor actual de la señal.</p><p>Si conoces cómo funcionan los observables en RxJS podrás notar que las señales pueden ser distintas ya que no emiten valores cómo lo hacen los observables, además de que no requieren una suscripción.</p><p>Además del método <code>set()</code>, también hay otras 2 maneras de cambiar una señal: <code>update()</code> y <code>mutate()</code>. El método <code>set()</code> reemplaza el valor de una señal con un valor nuevo, metafóricamente remplazado el contenido del "cajón" de la señal. Pásale el nuevo valor al método <code>set()</code>.</p><pre><code class="language-typescript">// Remplaza el valor
this.cantidad.set(cant);</code></pre><p>El método <code>update()</code> actualiza la señal en base a su valor actual. Pasa una función de "flecha" al método <code>update()</code>, esta provee el valor actual de la señal para que sea posible cambiarlo programáticamente según sea necesario. En el siguiente código la cantidad se duplica.</p><pre><code class="language-typescript">// Actualizar el valor de la señal en base al valor actual
this.cantidad.update(cant =&gt; cant * 2);</code></pre><p>El método <code>mutate()</code> modifica el contenido del valor de una señal, no el valor de la señal en sí. Úsalo con arreglos para modificar sus elementos y con objetos para modificar sus propiedades. En la siguiente línea de código se incrementa 20% el precio de un vehículo. </p><pre><code class="language-typescript">this.vehiculoSeleccionado.mutate(v =&gt; v.precio = v.precio + (v.precio * .20));</code></pre><p>Independientemente de la forma en cómo se modifica la señal, los consumidores serán notificados que ha sucedido un cambio, ellos pueden entonces leer el nuevo valor de la señal cuando es su turno de ejecución.</p><h2 id="c-mo-definir-una-se-al-computada"><strong>Cómo definir una señal computada</strong></h2><p>Frecuentemente tenemos variables en nuestro código que dependen de otras variables, por ejemplo, el precio total de un ítem es su precio unitario por el número o cantidad de ítems deseados de este tipo. Si el usuario cambia la cantidad queremos también cambiar el precio total, para lo que utilizamos <strong>señales computadas</strong> (<strong><strong>computed signals</strong></strong>). </p><p>Define una señal computada llamando la función <code>computed()</code> de creación de señales computadas, esta crea una nueva señal que depende de otras. Ahora pasemos a la función <code>computed()</code> una función que lleve a cabo las operaciones deseadas, esta tendrá acceso a la lectura de el valor de una o más señales para llevar a cabo su computo.</p><pre><code class="language-typescript">precioTotal = computed(() =&gt; this.vehiculoSeleccionado().precio * this.cantidad());

color = computed(() =&gt; this.precioTotal() &gt; 50000 ? 'verde' : 'azul');</code></pre><p>La primera línea de código de arriba define una señal computada <code>precioTotal</code> al llamar la función de creación <code>computed()</code>, la función que pasamos a esta función lee las señales <code>vehiculoSeleccionado</code> y <code>cantidad</code>, si cualquiera de estas cambia, la señal computada será notificada y leerá el nuevo valor la próxima vez que se ejecute.</p><p>La segunda línea define la señal computada <code>color</code>, que le asigna el valor <code>verde</code>o <code>azul</code> dependiendo del valor de la señal <code>precioTotal</code>. La plantilla puede vincular a esta señal para mostrar el estilo apropiado. </p><p>Una señal computada es sólo lectura y no puede ser modificada con los métodos <code>set()</code>, <code>update()</code> ni <code>mutate()</code>, además su valor se re-evalúa o re-computa cuando:</p><ul><li>Uno o más de sus señales dependientes ha cambiado.</li><li>Y el valor de la señal computada ha sido leído.</li></ul><p>La señal computada se "<em>memoiza", </em>lo que quiere decir que guarda el resultado evaluado, este es re-utilizado la próxima vez que es leído.</p><p>Digamos por ejemplo que tenemos lo siguiente en nuestra plantilla:</p><pre><code class="language-typescript">Precio extendido: {{ precioTotal() }}
Precio total: {{ precioTotal() }}
Cantidad a pagar: {{ precioTotal() }}</code></pre><p>La primera vez que la plantilla lea la señal computada <code>precioTotal</code>, el valor se calcula y se guarda en memoria, las siguientes 2 veces que se lee, se re-utiliza el valor almacenado anteriormente. Dicho valor no se re-calcula a menos que alguna de sus señales dependientes haya cambiado.</p><h2 id="c-mo-usar-un-efecto"><strong>Cómo usar un efecto</strong></h2><p>Podría haber momentos en que necesites ejecutar código en respuesta al cambio de alguna señal y que este código tenga efectos secundarios, por ello quiero decir que este código haga un llamado a alguna API o que realice alguna otra operación no relacionada a la señal, en estos casos debemos usar <code>effect()</code>. </p><p>Por ejemplo, digamos que quieres inspeccionar tu código en busca de errores (debug) y para ello deseas imprimir el valor de la señal usando <code>console.log</code> cada vez que esta sufra un cambio, como sabemos llamar <code>console.log</code> es un efecto secundario. </p><p>Para definir un efecto debemos llamar la función creacional <code>effect()</code>. Pasémosle a esta función la operación a realizar, la cual será ejecutada nuevamente cada vez que el código reaccione a un cambio en cualquiera de la señales dependientes.</p><pre><code class="language-typescript">effect(() =&gt; console.log(this.vehiculoSeleccionado()));</code></pre><p>La función <code>effect()</code> puede ser invocada desde otra función, pero frecuentemente es llamada desde el constructor u otro código de inicialización, dado que a su vez prepara un tipo de función manejadora (handler).</p><p>Alternativamente un efecto puede definirse de forma declarativa como se muestra a continuación:</p><pre><code class="language-typescript">e = effect(() =&gt; console.log(this.vehiculoSeleccionado()));</code></pre><p>Un efecto no debería cambiar el valor de ninguna señal, sin embargo si necesitas cambiar una señal en base a un cambio a otra señal dependiente es recomendable que utilices una señal computada en su lugar.</p><p>Cómo verás, no es muy común utilizar los efectos, aunque son útiles para imprimir valores por consola o para llamar APIs externas, pero no los uses para trabajar con RxJS ni Observables; habrá funcionalidades de las señales que serán útiles para convertir a y desde los observables.</p><h2 id="cu-ndo-usar-se-ales"><strong>Cuándo usar señales</strong></h2><p>Algunas sugerencias.</p><p>En primer lugar, continúa utilizando "handlers" en tus componentes como has venido haciendo hasta ahora para manejar o responder a las acciones de los usuarios. Acciones como realizar una selección de una lista desplegable, hacer clic en un botón o ingresar datos en una "caja de texto".</p><p>Usa una señal o señal computada en un componente para cualquier estado que pueda cambiar. En este contexto, estado se refiere a cualquier dato que sea administrado por el componente. Cualquier cosas desde una bander <code>estaCargandose</code> hasta la página actualmente mostrada con los datos seleccionados por el usuario podrían ser señales. Las señales son especialmente útiles cuando se muestran los datos en la plantilla que deben reaccionar a cambios dependientes de otras acciones.</p><p>Las señales compartidas deberían ser servicios. Digamos que tenemos un arreglo con los vehículos devueltos que se comparte entre componentes, este podría ser un servicio.</p><p>Continúa usando los observables para operaciones asíncronas como las llamadas a <code>http.get()</code>, cabe mencionar que hay otras funcionalidades que vendrán con las señales para equiparar más fielmente con los observables.</p><h2 id="concluyendo"><strong>Concluyendo</strong></h2><p>Las señales representan un avance mayúsculo en las capacidades de programación reactiva y detección de cambios de Angular. Este tutorial respondió a las preguntas: "¿Por qué?", "¿Qué?" y "¿Cómo?" así como "¿Dónde?" y "¿Cuándo?" también.</p><p>Las señales están disponibles en vista previa para desarrolladores en Angular v16, como parte de esta vista previa las señales se incluyen en el modelo de detección de cambios. Se espera que futuras capacidades de las señales mejorarán la detección de cambios y marcarán los componentes para revisión de una forma similar como se lleva a cabo actualmente al usar <code>OnPush</code> con la pipa asíncrona (async pipe). &nbsp;</p><p>Una forma sencilla y fácil de probar las señales es usar Stackblitz que es un editor de código en línea que trabaja muy bien con Angular y no requiere instalaciones. Para usar Stackblitz con señales:</p><ol><li>Navega al sitio de Stackblitz: <a href="http://www.stackblitz.com/">www.stackblitz.com</a>.</li><li>Haz clic en el icono de Angular para crear un proyecto Angular.</li><li>Edita el archivo <code>package.json</code> resultante y cambia las versiones de los paquetes de @angular a sus versiones más actuales "pre-realease" (Angular v16).</li><li>Guarda el proyecto para que se actualicen las dependencias.</li><li>Dale una probada a las señales.</li></ol><p>Para ver estos pasos en acción dale un vistazo al final del siguiente vídeo (en inglés):</p><figure class="kg-card kg-embed-card" data-test-label="fitted">
        <div class="fluid-width-video-container">
          <div style="padding-top: 56.17977528089888%;" class="fluid-width-video-wrapper">
            <iframe width="356" height="200" src="https://www.youtube.com/embed/oqYQG7QMdzw?feature=oembed" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="" title="Angular Signals: What? Why? and How?" name="fitvid1" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-optical-sizing: inherit; font-kerning: inherit; font-feature-settings: inherit; font-variation-settings: inherit; font-size: 22px; vertical-align: middle; position: absolute; top: 0px; left: 0px; width: 720px; height: 404.489px;"></iframe>
          </div>
        </div>
      </figure><p>También puedes empezar usando el enlace a mi proyecto <a href="https://stackblitz.com/edit/angular-signals-deborahk">https://stackblitz.com/edit/angular-signals-deborahk</a>. Asegúrate de crear una copia para que puedas realizar tus propios cambios.</p><p>¡Las señales llegaron! Van a mejorar la capacidad de detección de cambios y la reactividad de tu código, además de hacerlo de más fácil edición y lectura, además que son muy divertidas de usar. </p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ El Manual para principiantes C: Aprende las bases del lenguaje de programación C en sólo unas horas ]]>
                </title>
                <description>
                    <![CDATA[ Este manual sigue la regla 80/20. Aprenderás 80% del lenguaje de programación C en 20% del tiempo. Este enfoque te dará una visión amplia del lenguaje. Este manual no trata de cubrir todo lo relacionado con C, sino que se enfoca en el núcleo del lenguaje, tratando de simplificar los ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/el-libro-para-principiantes-c-aprende-las-bases-del-lenguaje-de-programacion-c-en-solo-unas-horas/</link>
                <guid isPermaLink="false">62df90c6b4def50851974a89</guid>
                
                    <category>
                        <![CDATA[ programacion c ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Palma ]]>
                </dc:creator>
                <pubDate>Tue, 11 Jun 2024 19:09:09 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/04/coverc-1-opt.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/the-c-beginners-handbook/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">The C Beginner's Handbook: Learn C Programming Language basics in just a few hours</a>
      </p><p>Este manual sigue la regla 80/20. Aprenderás 80% del lenguaje de programación C en 20% del tiempo.</p><p>Este enfoque te dará una visión amplia del lenguaje.</p><p>Este manual no trata de cubrir todo lo relacionado con C, sino que se enfoca en el núcleo del lenguaje, tratando de simplificar los temas más complejos.</p><p><a href="https://thevalleyofcode.com/download/c/">Puedes tener la versión PDF y ePub de este manual en inglés acá (hecha por el autor original)</a></p><p>¡Disfruta!</p><h2 id="tabla-de-contenidos">Tabla de Contenidos</h2><ol><li><a href="#intro">Introducción a C</a></li><li><a href="#variables">Variables y tipos</a></li><li><a href="#constantes">Constantes</a></li><li><a href="#operadores">Operadores</a></li><li><a href="#condicionales">Condicionales</a></li><li><a href="#bucles">Bucles,</a></li><li><a href="#arreglos">Arréglos</a></li><li><a href="#strings">Strings</a> (Cadenas de texto)</li><li><a href="#punteros">Punteros</a></li><li><a href="#funciones">Funciones</a></li><li><a href="#entradas-y-salidas">Entrada y Salida</a></li><li><a href="#scope">Alcance de las variables</a></li><li><a href="#variables-estaticas">Variables estáticas</a></li><li><a href="#variables-globales">Variables Globales</a></li><li><a href="#definiciones-de-tipos">Definiciones de tipos</a></li><li><a href="#tipos-enumerados">Tipos enumerados</a></li><li><a href="#estructuras">Estructuras</a></li><li><a href="#parametros-de-linea-de-comandos">Parámetros de línea de comando</a>s</li><li><a href="#archivos-de-cabecera">Archivos de Cabecera</a></li><li><a href="#preprocesador">Preprocesador</a></li><li><a href="#conclusion">Conclusión</a></li></ol><!--kg-card-begin: html--><h2 id="intro">Introducción a C</h2>
<!--kg-card-end: html--><p>C es probablemente el lenguaje de programación más conocido. Es usado como un lenguaje de referencia para cursos de programación alrededor de todo el mundo, y es probablemente el lenguaje más aprendido por las personas junto con Python y Java.</p><p>Recuerdo que fue mi segundo lenguaje de programación después de Pascal.</p><p>C no es sólo algo que usan los estudiantes para aprender programación. No es un lenguaje académico. Y diría que no es el lenguaje más fácil, porque C es un lenguaje de programación de bajo nivel.</p><p>Al día de hoy, C es ampliamente usado en dispositivos integrados, y alimenta la mayoría de los servidores de internet, los cuales están construidos usando Linux. El Kernel de Linux está construido usando C, esto significa también que alimenta el núcleo de todos los dispositivos Android. Podríamos decir que justo en este momento, el código C se ejecuta en un gran número de aplicaciones en el mundo entero. Lo cual es bastante notable.</p><p>Cuando fue creado, C se consideraba un lenguaje de alto nivel, porque era portable entre máquinas. Ahora damos por sentado que podemos ejecutar un programa escrito en una Mac, Windows o Linux, usando tal vez Node.js o Python.</p><p>Hace algún tiempo, esto simplemente no era el caso. Lo que C trajo a la mesa era un lenguaje simple de implementar y que tenía un compilador que podía ser fácilmente portado a diferentes máquinas.</p><p>Dije un compilador: C es un lenguaje compilado, como Go, Java, Swift o Rust. Otros lenguajes de programación populares como Python, Ruby o JavaScript son interpretados. La diferencia consiste en: un lenguaje compilado genera un archivo binario que puede ser directamente ejecutado y distribuido.</p><p>C no tiene recolección de basura. Esto significa que tenemos que manejar la memoria por nuestra cuenta. Es una tarea compleja, y una que requiere mucha de nuestra atención para prevenir bugs, pero esto hace también que C sea ideal para escribir programas para dispositivos integrados como Arduino.</p><p>C no esconde la complejidad y capacidades de la máquina debajo. Tienes mucho poder, una vez que sabes qué puedes hacer.</p><p>Quiero presentarte el primer programa C, el cual llamaremos ¡"Hola Mundo!"</p><p>hola. c</p><!--kg-card-begin: markdown--><pre><code>#include &lt;stdio.h&gt;

int main(void) {
    printf("Hola Mundo!");
}
</code></pre>
<!--kg-card-end: markdown--><p>Describamos el código del programa: primero importamos la librería <code>stdio</code> (el nombre significa librería estándar de entradas y salidas).</p><p>Esta librería nos da acceso a las funciones I/O, es decir de entrada y salida (input/output).</p><p>C es un lenguaje muy pequeño en su núcleo, y cualquier cosa que no sea parte del núcleo se provee a través de librerías. Algunas de estas librerías están construidas por programadores normales que las habilitan para que otros los usen. Algunas librerías están integradas en el compilador. Como <code>stdio</code> y otras.</p><p><code>stdio</code> es la librería que provee la función <code>printf()</code>.</p><p>Esta función está envuelta en la función <code>main()</code>, que es el punto de entrada de cualquier programa en C.</p><p>Pero entonces, ¿Qué es una función?</p><p>Una función es una rutina que toma uno o más argumentos, y devuelve un valor.</p><p>En el caso de la función <code>main()</code> no recibe argumentos, y retorna un entero. Identificamos esto usando la palabra clave <code>void</code> para el argumento, y la palabra clave <code>int</code> para el valor de retorno.</p><p>La función tiene un cuerpo, el cual está entre los paréntesis de llave. Dentro del cuerpo tenemos todo el código que la función necesita para realizar sus operaciones.</p><p>La función <code>printf()</code> está escrita de forma diferente, como podrás ver. Esta no tiene un valor de retorno definido, y le pasamos una cadena de texto entre comillas dobles. Nosotros no especificamos el tipo de argumento.</p><p>Esto es porque esta es una invocación de función. En algún lugar, dentro de la librería <code>stdio</code>, la función <code>printf</code> está definida como: </p><!--kg-card-begin: markdown--><pre><code>int printf(const char *format, ... );
</code></pre>
<!--kg-card-end: markdown--><p>No necesitas entender qué significa esto por ahora, pero, en resumen, esta es la definición. Y cuando llamamos a <code>printf("Hola Mundo!");</code> ahí es donde se ejecuta la función.</p><p>La función <code>main()</code> que definimos arriba: </p><!--kg-card-begin: markdown--><pre><code>#include &lt;stdio.h&gt;

int main(void) {
    printf("¡Hola Mundo!");
}</code></pre>
<!--kg-card-end: markdown--><p>será ejecutada por el sistema operativo cuando a su vez, el programa sea ejecutado.</p><p>¿Cómo ejecutamos un programa C?</p><p>Como mencioné, C es un lenguaje compilado. Para ejecutar el programa debemos compilarlo primero. Cualquier computador con Linux o MacOS ya viene con un compilador C integrado. Para Windows, puedes usar el subsistema de Windows para Linux (WSL).</p><p>Cuando abras la terminal puedes escribir <code>gcc</code>, y este comando debería retornar un error diciendo que no especificaste un archivo:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-1.png" class="kg-image" alt="imagen-1" width="465" height="188" loading="lazy"><figcaption>Linux Ubuntu Terminal</figcaption></figure><p>Esto está bien. Significa que el compilador está ahí, y podemos comenzar a usarlo.</p><p>Ahora escribiremos el programa de arriba en el archivo <code>hola.c</code>. Puedes usar cualquier editor, para mantener la simplicidad usaré el editor <code>nano</code> en la línea de comandos:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-2.png" class="kg-image" alt="imagen-2" width="465" height="188" loading="lazy"></figure><p>Escribe el programa:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-3.png" class="kg-image" alt="imagen-3" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/12/imagen-3.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-3.png 720w" sizes="(min-width: 720px) 720px" width="720" height="394" loading="lazy"></figure><p>Ahora presiona <code>ctrl-x</code> para salir:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-4.png" class="kg-image" alt="imagen-4" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/12/imagen-4.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-4.png 720w" sizes="(min-width: 720px) 720px" width="720" height="394" loading="lazy"></figure><!--kg-card-begin: markdown--><p>Confirma presionando la tecla <code>S</code>, y luego presiona enter para confirmar el nombre del archivo:</p>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-5.png" class="kg-image" alt="imagen-5" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/12/imagen-5.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-5.png 720w" sizes="(min-width: 720px) 720px" width="720" height="394" loading="lazy"></figure><p>Esto de debería traer de vuelta a la terminal:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-6.png" class="kg-image" alt="imagen-6" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/12/imagen-6.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-6.png 720w" sizes="(min-width: 720px) 720px" width="720" height="394" loading="lazy"></figure><p>Ahora escribe</p><!--kg-card-begin: markdown--><pre><code>gcc hola.c -o hola
</code></pre>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-7.png" class="kg-image" alt="imagen-7" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/12/imagen-7.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-7.png 720w" sizes="(min-width: 720px) 720px" width="720" height="394" loading="lazy"></figure><p>Esto debería haber generado un ejecutable <code>hola</code>. Ahora escribe <code>./hola</code> para ejecutarlo:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-8.png" class="kg-image" alt="imagen-8" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/12/imagen-8.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-8.png 720w" sizes="(min-width: 720px) 720px" width="720" height="394" loading="lazy"></figure><p>Antepongo <code>./</code> al nombre del programa para decirle al terminal que el comando es para el directorio actual.</p><p>¡Impresionante!</p><p>Ahora si invocas <code>ls -al hola</code>, verás que el programa es de tan solo 16KB:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-9.png" class="kg-image" alt="imagen-9" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/12/imagen-9.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-9.png 720w" sizes="(min-width: 720px) 720px" width="720" height="394" loading="lazy"></figure><p>Este es uno de los pros de C: está altamente optimizado, esta también, es una de las razones por las que es bueno para sistemas integrados que tienen una cantidad limitada de recursos.</p><!--kg-card-begin: html--><h2 id="variables">Variables y tipos</h2><!--kg-card-end: html--><p>C es un lenguaje de tipo estático.</p><p>Esto significa que cualquier variable tiene un tipo asociado, y si tipo es conocido al momento de la compilación.</p><p>Esto es muy distinto a como trabajamos con variables en Python, JavaScript, PHP y otros lenguajes interpretados.</p><p>Cuando creas una variable en C, tienes que especificar el tipo de variable en la declaración.</p><p>En este ejemplo iniciamos una variable <code>edad</code> con el tipo <code>int</code>:</p><!--kg-card-begin: markdown--><pre><code>int edad;
</code></pre>
<!--kg-card-end: markdown--><p>Un nombre de variable puede tener mayúsculas, minúsculas, puede contener dígitos y el guion bajo, pero no puede empezar con un dígito. <code>EDAD</code> y <code>Edad10</code> son nombres de variables válidos, <code>1edad</code> no lo es.</p><p>También puedes iniciar la declaración de una variable especificando su valor inicial:</p><!--kg-card-begin: markdown--><pre><code>int edad = 37;
</code></pre>
<!--kg-card-end: markdown--><p>Una vez que declaras una variable podrás usarla en el código de tu programa. Puedes cambiar su valor en cualquier momento, usando el operador <code>=</code>, por ejemplo en <code>edad=100; </code> (siempre que el nuevo valor sea del mismo tipo).</p><p>En este caso:</p><!--kg-card-begin: markdown--><pre><code>#include &lt;stdio.h&gt;

int main(void) {
    int edad = 0;
    edad = 37.2;
    printf("%u", edad);
}</code></pre>
<!--kg-card-end: markdown--><p>El compilador lanzará una advertencia en tiempo de compilación, y convertirá el número decimal en un número entero.</p><p>Los tipos de datos integrados en C son <code>int</code>, <code>char</code>, <code>short</code>, <code>long</code>, <code>float</code>, <code>double</code> y <code>long double</code>. Aprendamos más sobre ellos.</p><h3 id="n-meros-enteros">Números enteros</h3><p>C nos provee los siguientes tipos para definir valores enteros:</p><ul><li><code>char</code></li><li><code>int</code></li><li><code>short</code></li><li><code>long</code></li></ul><p>La mayoría del tiempo es probable que uses <code>int</code> para almacenar enteros. Pero en algunos casos podrías querer usar una de las otras 3 opciones.</p><p>El tipo <code>char</code> es comúnmente usado para almacenar letras de la tabla ASCII, pero puede ser usado para guardar pequeños enteros desde <code>-128</code> a <code>127</code>. Esto usa al menos 1 byte.</p><p><code>int</code> usa al menos 2 bytes. <code>short</code> usa al menos 2 bytes. <code>long</code> usa al menos 4 bytes.</p><p>Como puedes ver, no se nos garantiza los mismos valores para diferentes entornos. Sólo tenemos una indicación. El problema es que el número exacto de bits que puede ser almacenado en cada tipo de dato depende de la implementación y arquitectura.</p><p>Tenemos garantizado que <code>short</code> no es más grande que <code>int</code>. Y tenemos garantizado que <code>long</code> no es más pequeño que <code>int</code>.</p><p>El estándar de especificaciones ANSI C determina los valores mínimos de cada tipo, y gracias a este, podemos al menos saber cuál es el valor mínimo que podemos esperar tener a nuestra disposición.</p><p>Si estás programando C en un Arduino, diferentes placas tendrán diferentes límites.</p><p>En una placa Arduino Uno, <code>int</code> almacena un valor de 2 byte, con rangos desde <code>-32,768</code> a <code>32,767</code>. En Arduino MKR 1010 <code>int</code> almacena un valor de 4 bytes, con rangos desde <code>-2,147,483,648</code> a <code>2,147,483,647</code>. Una gran diferencia.</p><p>En todas las placas Arduino, <code>short</code> almacena valores de 2 bytes, con rangos desde <code>-32,768</code> a <code>32,767</code>. <code>long</code> almacena 4 bytes, con rangos desde <code>-2,147,483,648</code> a <code>2,147,483,647</code>.</p><h3 id="enteros-sin-signo">Enteros sin signo</h3><p>Para todos los tipos de datos arriba, podemos anteponer <code>unsigned</code> para comenzar el rango desde <code>0</code>, en vez de números negativos. Esto podría tener sentido en muchas formas.</p><ul><li><code>unsigned char</code> tiene un rango de <code>0</code> hasta al menos <code>255</code></li><li><code>unsigned int</code> tiene un rango de <code>0</code> hasta al menos <code>65,535</code></li><li><code>unsigned short</code> tiene un rango de <code>0</code> hasta al menos <code>65,535</code></li><li><code>unsigned long</code> tiene un rango de <code>0</code> hasta al menos <code>4,294,967,295</code></li></ul><h3 id="problema-con-el-desbordamiento">Problema con el desbordamiento</h3><p>Dados todos estos límites puede surgir una duda: ¿Cómo podemos estar seguros de que nuestros números no excederán los límites? Y ¿Qué pasa si excedimos estos límites?</p><p>Si tienes un número de tipo <code>unsigned int</code> en 255, y lo incrementas, tendrás 256 de retorno, como podrías esperar. Si tienes un número de tipo <code>unsigned char</code> en 255, y lo incrementas, obtendrás un <code>0</code> de retorno. Este se resetea empezando desde el posible valor inicial.</p><p>Si tienes un número de tipo <code>unsigned char</code> en 255 y luego sumas 10 a él, obtendrás el número 9:</p><!--kg-card-begin: markdown--><pre><code>#include &lt;stdio.h&gt;

int main(void) {
    unsigned char j = 255;
    j = j + 10:
    printf("%u", j); /*9*/
}
</code></pre>
<!--kg-card-end: markdown--><p>Si no tienes un valor con signo, el comportamiento es indefinido. Esto básicamente te dará un número gigante que puede variar, como en este caso:</p><!--kg-card-begin: markdown--><pre><code>#include &lt;stdio.h&gt;

int main(void) {
    char j = 127;
    j = j + 10;
    printf("%u", j); /* 4294967177 */
}
</code></pre>
<!--kg-card-end: markdown--><p>En otras palabras, C no te protege de salirte de los límites de un tipo. Tienes que hacerte cargo por ti mismo.</p><h3 id="advertencias-cuando-declaras-el-tipo-equivocado">Advertencias cuando declaras el tipo equivocado</h3><p>Cuando declaras una variable y la inicializas con el valor equivocado, el compilador <code>gcc</code> (el que probablemente estés usando) debería advertirte:</p><!--kg-card-begin: markdown--><pre><code>#include &lt;stdio.h&gt;

int main(void) {
    char j = 1000;
}
</code></pre>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-10.png" class="kg-image" alt="imagen-10" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/12/imagen-10.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2022/12/imagen-10.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-10.png 1260w" sizes="(min-width: 720px) 720px" width="1260" height="184" loading="lazy"></figure><p>Y también te advierte en asignaciones directas:</p><!--kg-card-begin: markdown--><pre><code>#include &lt;stdio.h&gt;

int main(void) {
    char j;
    j = 1000;
}
</code></pre>
<!--kg-card-end: markdown--><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-11.png" class="kg-image" alt="imagen-11" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/12/imagen-11.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2022/12/imagen-11.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2022/12/imagen-11.png 1260w" sizes="(min-width: 720px) 720px" width="1260" height="184" loading="lazy"></figure><p>Pero no te advertirá si aumentas el número usando <code>+=</code>, por ejemplo: </p><!--kg-card-begin: markdown--><pre><code>#include &lt;stdio.h&gt;

int main(void) {
    char j = 0;
    j += 1000;
}
</code></pre>
<!--kg-card-end: markdown--><h3 id="n-meros-de-punto-flotante">Números de punto flotante</h3><p>Los tipos de punto flotante (<code>float</code>) pueden representar un conjunto de valores mucho más grandes de lo que pueden hacer los enteros (<code>int</code>), también pueden representar fracciones, algo que los enteros no pueden hacer.</p><p>Al usar números de punto flotante, representamos lo números como números decimales multiplicados por potencias de 10.</p><p>Tal vez veas números de punto flotante escritos como:</p><ul><li><code>1.29e-3</code></li><li><code>-2.3e+5</code></li></ul><p>y de otras formas aparentemente extrañas.</p><p>Los siguientes tipos:</p><ul><li><code>float</code></li><li><code>double</code></li><li><code>long double</code></li></ul><p>son usados para representar números con punto decimal (tipos de punto flotante). Todos ellos pueden representar números positivos y negativos.</p><p>Los requerimientos mínimos para cualquier implementación en C es que <code>float</code> puede representar un rango entre <code>10^-37</code> y <code>10^+37</code>, y típicamente es implementado usando 32 bits. <code>double</code> puede representar conjuntos más grandes de números. <code>long double</code> puede tener incluso más números.</p><p>Las cifras exactas, al igual que con los números enteros, dependen de la implementación.</p><p>En una Mac moderna, un <code>float</code> es representado en 32 bits, y tiene una precisión de 24 bits significativos, de los cuales 8 bits son usados para codificar el exponente.</p><p>Un número <code>double</code> se representa en 64 bits, con una precisión de 53 bits significativos, 11 bits de los cuales son usados para codificar el exponente.</p><p>El tipo <code>long double</code> es representado en <code>80</code> bits, tiene una precisión de 64 bits significativos. 15 bits son usados para codificar el exponente.</p><p>En tu equipo, ¿cómo puedes determinar el tamaño específico de los tipos? Puedes escribir un programa para hacer eso:</p><pre><code class="language-c">#include &lt;stdio.h&gt;

int main(void) {
  printf("char size: %lu bytes\n", sizeof(char));
  printf("int size: %lu bytes\n", sizeof(int));
  printf("short size: %lu bytes\n", sizeof(short));
  printf("long size: %lu bytes\n", sizeof(long));
  printf("float size: %lu bytes\n", sizeof(float));
  printf("double size: %lu bytes\n", 
    sizeof(double));
  printf("long double size: %lu bytes\n", 
    sizeof(long double));
}
</code></pre><p>En mi sistema, Windows moderno, imprime:</p><pre><code>char size: 1 bytes
int size: 4 bytes
short size: 2 bytes
long size: 8 bytes
float size: 4 bytes
double size: 8 bytes
long double size: 16 bytes
</code></pre><!--kg-card-begin: html--><h2 id="constantes">Constantes</h2>
<!--kg-card-end: html--><p>Hablemos ahora de las constantes:</p><p>Una constante se declara de forma similar a las variables, excepto que anteponemos la palabra reservada <code>const</code> y siempre tienes que especificar un valor.</p><p>De la siguiente forma: </p><pre><code>const int age = 37;</code></pre><p>Esto es C perfectamente válido, aunque es común declarar las constantes con mayúsculas, así:</p><pre><code>const int AGE = 37;</code></pre><p>Esta es sólo una convención, pero una que puede ayudarte mucho mientras escribes o lees un programa C, ya que mejora su legibilidad. Los nombres en mayúscula significan constantes, nombres en minúsculas significas variables.</p><p>Un nombre de constante sigue las mismas reglas que los nombres de variables: pueden contener letras mayúsculas o minúsculas, pueden contener dígitos y el guión bajo (<code>_</code>), pero no pueden comenzar con un dígito. <code>EDAD</code> y <code>Edad10</code> son nombres de variables válidos, <code>1EDAD</code> no lo es.</p><p>Otra forma de definir constantes y mediante el uso de la siguiente sintaxis: </p><pre><code class="language-c">#define EDAD 37</code></pre><p>En este caso, tu no necesitas agregar el tipo, y tampoco necesitas agregar el signo igual <code>=</code>, y omites el punto y coma al final.</p><p>El compilador C inferirá el tipo del valor especificado en tiempo de compilación.</p><!--kg-card-begin: html--><h2 id="operadores">Operadores</h2><!--kg-card-end: html--><p>C ofrece una amplia variedad de operadores que podemos usar para operar en los datos.</p><p>En particular, podemos definir varios grupos de operadores:</p><ul><li>operadores aritméticos</li><li>operadores de comparación</li><li>operadores lógicos</li><li>operadores de asignación compuestos.</li><li>operadores bitwise</li><li>operadores de punteros</li><li>operadores de estructura</li><li>operadores misceláneos</li></ul><p>En esta sección voy a detallar todos ellos, usando dos variables imaginarias <code>a</code> y <code>b</code> como ejemplos.</p><p>Mantendré los operadores bitwise, operadores de estructura y punteros fuera de esta lista por simplicidad</p><h2 id="operadores-aritm-ticos">Operadores aritméticos</h2><p>En este macro-grupo separaré operadores binarios y unarios.</p><p>Los operadores binarios utilizan dos operandos:</p><!--kg-card-begin: html--><table>
<thead>
<tr>
<th>Operator</th>
<th>Name</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>=</code></td>
<td>Assignment</td>
<td><code>a = b</code></td>
</tr>
<tr>
<td><code>+</code></td>
<td>Addition</td>
<td><code>a + b</code></td>
</tr>
<tr>
<td><code>-</code></td>
<td>Subtraction</td>
<td><code>a - b</code></td>
</tr>
<tr>
<td><code>*</code></td>
<td>Multiplication</td>
<td><code>a * b</code></td>
</tr>
<tr>
<td><code>/</code></td>
<td>Division</td>
<td><code>a / b</code></td>
</tr>
<tr>
<td><code>%</code></td>
<td>Modulo</td>
<td><code>a % b</code></td>
</tr>
</tbody>
</table><!--kg-card-end: html--><p>Los operadores unarios toman sólo un operando:</p><!--kg-card-begin: html--><table>
<thead>
<tr>
<th>Operator</th>
<th>Name</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>+</code></td>
<td>Unary plus</td>
<td><code>+a</code></td>
</tr>
<tr>
<td><code>-</code></td>
<td>Unary minus</td>
<td><code>-a</code></td>
</tr>
<tr>
<td><code>++</code></td>
<td>Increment</td>
<td><code>a++</code> or <code>++a</code></td>
</tr>
<tr>
<td><code>--</code></td>
<td>Decrement</td>
<td><code>a--</code> or <code>--a</code></td>
</tr>
</tbody>
</table><!--kg-card-end: html--><p>La diferencia entre <code>a++</code> y <code>++a</code> es que <code>a++</code> incrementa la variable <code>a</code> después de usarla. <code>++a</code> incrementa la variable antes de usarla.</p><p>Por ejemplo:</p><figure class="kg-card kg-code-card"><pre><code>int a = 2; 
int b; 
b = a++ /* b es 2, a es 3*/ 
b = ++a /* b es 4, a es 4*/</code></pre><figcaption>Ejemplo</figcaption></figure><p>Lo mismo aplica para el operador decremento.</p><h3 id="operadores-de-comparaci-n">Operadores de comparación</h3><!--kg-card-begin: html--><table>
<thead>
<tr>
<th>Operator</th>
<th>Name</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>==</code></td>
<td>Equal operator</td>
<td><code>a == b</code></td>
</tr>
<tr>
<td><code>!=</code></td>
<td>Not equal operator</td>
<td><code>a != b</code></td>
</tr>
<tr>
<td><code>&gt;</code></td>
<td>Bigger than</td>
<td><code>a &gt; b</code></td>
</tr>
<tr>
<td><code>&lt;</code></td>
<td>Less than</td>
<td><code>a &lt; b</code></td>
</tr>
<tr>
<td><code>&gt;=</code></td>
<td>Bigger than or equal to</td>
<td><code>a &gt;= b</code></td>
</tr>
<tr>
<td><code>&lt;=</code></td>
<td>Less than or equal to</td>
<td><code>a &lt;= b</code></td>
</tr>
</tbody>
</table><!--kg-card-end: html--><p>‌</p><h2 id="operadores-l-gicos">Operadores lógicos</h2><p>‌</p><ul><li><code>!</code> No (NOT, ejemplo: <code>!a</code>)</li><li><code>&amp;&amp;</code> Y (AND, ejemplo: <code>a &amp;&amp; b</code>)</li><li><code>||</code> O (OR, ejemplo: <code>a || b</code>)</li></ul><p>Estos operadores son geniales cuando trabajamos con valores booleanos.</p><h2 id="operadores-de-asignaci-n-compuestos">Operadores de asignación compuestos</h2><p>Estos operadores son útiles para realizar asignaciones y a la vez realizar cálculos aritméticos:</p><!--kg-card-begin: html--><table>
<thead>
<tr>
<th>Operator</th>
<th>Name</th>
<th>Example</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>+=</code></td>
<td>Addition assignment</td>
<td><code>a += b</code></td>
</tr>
<tr>
<td><code>-=</code></td>
<td>Subtraction assignment</td>
<td><code>a -= b</code></td>
</tr>
<tr>
<td><code>*=</code></td>
<td>Multiplication assignment</td>
<td><code>a *= b</code></td>
</tr>
<tr>
<td><code>/=</code></td>
<td>Division assignment</td>
<td><code>a /= b</code></td>
</tr>
<tr>
<td><code>%=</code></td>
<td>Modulo assignment</td>
<td><code>a %= b</code></td>
</tr>
</tbody>
</table><!--kg-card-end: html--><h2 id="operador-ternario">Operador Ternario</h2><p>El operador ternario es el único operador en C que trabaja con 3 operandos, y es una forma corta de expresar condicionales.</p><p>Así luce:</p><p><code>&lt;condición&gt; ? &lt;expresión&gt; : &lt;expresión&gt;</code></p><p>Ejemplo:</p><p><code>a ? b : c</code>‌</p><p>Si <code>a</code> retorna <code>true</code>, entonces se ejecuta <code>b</code>, de otra forma se ejecuta <code>c</code>.</p><p>El operador ternario es funcionalmente igual que un condicional if/else, excepto que su expresión es más corta y que se puede insertar en una expresión.</p><h2 id="sizeof">sizeof</h2><p>El operador <code>sizeof</code> retorna el tamaño del operando que pases cómo argumento. Puedes pasar una variable, o incluso un tipo.</p><p>Ejemplos de uso: </p><pre><code class="language-c">#include &lt;stdio.h&gt; 
int main(void) { 
	int edad = 37; 
    print("%ld\n", sizeof(edad)); 
    print("%ld", sizeof(int)); 
}</code></pre><h2 id="precedencia-de-operadores">Precedencia de operadores</h2><p>Con todos estos operadores (y más, que no he cubierto en este artículo, incluyendo bitwise, operadores de estructura, y operadores de puntero), debemos poner atención cuando los usamos juntos en una única expresión.</p><p>Supón que tienes esta operación:</p><pre><code class="language-C">int a = 2; 
int b = 4; 
int c = b + a * a / b - a;</code></pre><p>¿Cuál es el valor de <code>c</code>? ¿Acaso se ejecuta la adición antes que la multiplicación y la división?</p><p>Hay un conjunto de reglas que nos ayudarán a resolver este acertijo.</p><p>En orden de menor a mayor precedencia, tenemos:</p><ul><li>el operador de asignación <code>=</code></li><li>los operadores binarios <code>+</code> y <code>-</code></li><li>los operadores <code>*</code> y <code>/</code></li><li>los operadores unarios <code>+</code> y <code>-</code></li></ul><p>Los operadores también tienen la regla de asociatividad, la cual siempre es de izquierda a derecha, excepto por los operadores unarios y el operador de asignación.</p><p>En:</p><pre><code class="language-C">   int c = b + a * a / b - a</code></pre><p>Primero ejecutamos <code>a * a / b</code>, del cual, dada la regla de izquierda-a-derecha, podemos separarlo en <code>a * a</code> y el resultado dividirlo entre <code>/b</code>: <code>2* 2 = 4</code>, <code>4 / 4 = 1</code>. &nbsp;</p><p>Luego podemos realizar la suma y la sustracción: <code>4 + 1 - 2</code>. El valor de <code>c</code> es <code>3</code>.</p><p>En cualquier caso, sin embargo, querrás asegurarte de darte cuenta de que puedes usar paréntesis para hacer que cualquier expresión sea más fácil de leer y de comprender.</p><p>Los paréntesis tienen prioridad más alta sobre cualquier cosa.</p><p>La expresión de más arriba puede ser reescrita como:</p><pre><code class="language-C">int c = b + ((a * a) / b) - a;</code></pre><p>Ahora no tenemos que pensar tanto en ella.</p><!--kg-card-begin: html--><h2 id="condicionales">Condicionales</h2><!--kg-card-end: html--><p>Cualquier lenguaje de programación brinda al programador opciones y la habilidad de realizar tomar decisiones.</p><p>Queremos hacer X en algunos casos, Y en otros casos.</p><p>Queremos verificar datos, y tomar decisiones en base al estado de esos datos.</p><p>C nos ofrece dos formas de hacerlo.</p><p>Primero está la declaración <code>if</code>, con su ayudante <code>else</code>, y la segunda es la declaración <code>switch</code>.</p><h2 id="if">if</h2><p>En una declaración <code>if</code>, puedes verificar si una confición es verdadera, y luego ejecutar el código que está entre los paréntesis de llave: </p><pre><code class="language-C">int a = 1; 
if (a == 1) { 
  /* haz algo*/ 
}</code></pre><p>Puedes agregar un bloque <code>else</code> para ejecutar código distinto, si en la condición original el argumento se evalúa como falso: </p><pre><code class="language-C">int a = 1; 
if (a == 2) { 
   /* haz algo */ 
} else { 
   /* haz esto otro */ 
}</code></pre><p>Debes tener cuidado con una causa común de errores: siempre usa el operador de comparación <code>==</code> cuando compares, y no el operador de asignación <code>=</code>. Si no lo haces, el condicional <code>if</code> siempre será verdad, a menos que el argumento sea <code>0</code>, por ejemplo si haces: </p><pre><code class="language-C">int a = 0; 
if (a = 0 ) { 
  /* nunca será invocado*/ 
}</code></pre><p>¿Porqué pasa esto? Porque el operador condicional buscará un resultado booleano (el resultado de la comparación), y el número <code>0</code> siempre equivale a un valor falso. Todos los demás números equivalen a verdadero, incluyendo los números negativos.</p><p>Puedes tener múltiples bloques <code>else</code> agrupando varias sentencias <code>if</code>:</p><pre><code class="language-C">int a = 1; 
if (a == 2) { 
  /* haz algo */ 
} else if ( a == 1 ) { 
  /* es otra cosa */ 
} else { 
  /* es esta otra cosa */ 
}</code></pre><h2 id="switch">switch</h2><p>Si necesitas hacer muchos bloques if/else/if para realizar una verificación, tal vez necesites revisar el valor exacto de una variable, entonces <code>switch</code> puede ser muy útil para ti.</p><p>Puedes proveer variables como condiciones, y una serie de puntos de entrada para cada caso (<code>case</code>) esperado: </p><pre><code class="language-C">int a = 1; 
switch (a) { 
  case 0: 
    /* hace algo si a = 0 */ 
  	break; 
  case 1: 
    /* hace otra cosa si a = 1 */ 
    break; 
  case 2: 
    /* hace otra cosa si a = 2 */ 
    break; 
}</code></pre><p>Necesitamos la palabra reservada <code>break</code> al final de cada caso para evitar que el siguiente caso sea ejecutado cuando el anterior haya terminado. Este efecto "cascada" puede ser útil en algunas formas creativas.</p><p>Puedes agregar un "comodín" al final, etiquetado como <code>default</code>:</p><pre><code class="language-C">default: int a = 1; 
switch (a) { 
  case 0: 
    /* hace algo si a = 0 */ 
    break; 
  case 1: 
    /* hace otra cosa si a = 1 */ 
    break; 
  case 2: 
    /* hace otra cosa si a = 2 */ 
    break; 
  default: 
    /* Aquí se manejan todos los otros casos */ 
    break; 
 }</code></pre><!--kg-card-begin: html--><h2 id="bucles">Bucles</h2><!--kg-card-end: html--><p>C nos ofrece tres formas de ejecutar bucles o también conocidos como ciclos: ciclo <strong>for</strong>, ciclo <strong>while</strong> y ciclo <strong>do while</strong>. Ellos te permiten iterar sobre arrays, pero con algunas diferencias. Veámoslas en detalle.</p><h3 id="ciclo-for">Ciclo for</h3><p>El primero y probablemente la forma más común de realizar un ciclo es el ciclo <strong>for.</strong></p><p>Al usar la palabra reservada <code>for</code> podemos definir las <em>reglas </em>del bucle por adelantado, y luego definimos el bloque de código que se ejecutará repetidamente. </p><p>Algo como esto: </p><pre><code class="language-C">for (int i = 0 ; i &lt;= 10 ; i++){ 
  /* instrucciones que serán repetidas */ 
}</code></pre><p>El bloque <code>(int i = 0; i&lt;= 10; i++)</code> contiene 3 partes de los detalles del bucle:</p><ul><li>La condición inicial (<code>int i = 0</code>)</li><li>La prueba (<code>i &lt;= 10</code>)</li><li>El incremento (<code>i++</code>)</li></ul><p>Primero definimos la variable del bucle, en este caso <code>i</code>. &nbsp;<code>i</code> es un nombre de variable común usado en los bucles, junto con <code>j</code> para los ciclos anidados (un bucle dentro de un bucle), lo cual es sólo una convención.</p><p>La variable es inicializada en el valor <code>0</code>, y se realiza la primera iteración. Luego esta es incrementada según dice la parte del incremento (<code>i++</code> en este caso, incrementando por <code>1</code>), y todo el ciclo se repite hasta que tienes el número <code>10</code>.</p><p>Dentro del bloque principal del bucle, podemos acceder a la variable <code>i</code> para saber en qué iteración vamos. Este programa imprimirá en pantalla <code>0 1 2 3 4 5 6 7 8 9 10</code>:</p><pre><code class="language-C">for (int i = 0; i &lt;= 10; i++) { 
  /* Instrucciones a repetir */ 
  printf("%u ", i); 
}</code></pre><p>Los ciclos también pueden empezar desde un número más grande y descender a uno más pequeño, como este: </p><pre><code class="language-C">for (int i = 10; i &gt; 0; i--) { 
  /* instrucciones a repetir */ 
}</code></pre><p>Además puedes incrementar la variable de iteración por 2 o cualquier otro valor : </p><pre><code class="language-C">for (int i = 0; i &lt; 1000; i = i+30){ 
  /* instrucciones a repetir */ 
}</code></pre><h3 id="ciclo-while">Ciclo While</h3><p>El <strong>ciclo while</strong> es más simple de escribir que un ciclo <code>for</code>, porque requiere un poco más de trabajo de tu parte.</p><p>En vez de definir toda la información del loop arriba, cuando inicias el loop, como lo harías en un ciclo <code>for</code>, al usar <code>while</code> sólo verificas una condición: </p><pre><code class="language-C">while ( i &lt; 10){ 
  /* hace algo cuando i es menor que 10 */ 
}</code></pre><p>Esto asume que <code>i</code> ya está definido e inicializado con un valor.</p><p>Y este bucle será un ciclo<strong> infinito</strong> a menos que incrementes la variable <code>i</code> en algún punto dentro del ciclo. Un ciclo infinito es malo porque este bloqueará el programa, sin permitir que ocurran otras cosas.</p><p>Esto es lo necesario para un ciclo while "correcto": </p><pre><code class="language-C">int i = 0; 
while ( i &lt; 10 ) { 
  /* haz algo */ 
  i++; 
}</code></pre><p>Hay una excepción a esto, la veremos en un minuto. Antes déjame presentarte <code>do while</code></p><h3 id="ciclo-do-while">Ciclo Do while</h3><p>Los ciclos while son geniales, pero existirán veces en las que necesitarás hacer una cosa particular: Tú quieres que siempre se ejecute un bloque, y luego <em>tal vez</em> repetirlo.</p><p>Esto se hace usando la palabra clave <code>do while</code>. De una forma muy similar al ciclo <code>while</code>, pero con una leve diferencia: </p><pre><code class="language-C">int i = 0; 
do { 
  /* hace algo */ 
  i++; 
} while (i &lt; 10);</code></pre><p>El bloque que contiene el comentario <code>/* hace algo*/</code>, siempre será ejecutado, a lo menos una vez, sin importar si cumple la condición de abajo.</p><p>Luego, mientras <code>i</code> sea menor que 10, repetiremos el bloque.</p><h3 id="saliendo-de-un-bucle-usando-la-palabra-reservada-break">Saliendo de un bucle usando la palabra reservada break</h3><p>En C todos los bucles tienen una forma salir, es decir de detener las repeticiones en cualquier momento, inmediatamente, sin importar las condiciones definidas para el bucle.</p><p>Esto lo logramos usando la palabra clave <code>break</code>.</p><p>Esto es útil en muchos casos. Tal vez quieras verificar el valor de una variable, por ejemplo: </p><pre><code class="language-C">for (int i = 0; i &lt;= 10; i++) { 
 if ( i == 4 &amp;&amp; algunaVariable == 10) { 
   break; 
 } 
}</code></pre><p>Tener esta opción de salida de un bucle es particularmente interesante para el ciclo <code>while</code> (y también para el <code>do while</code>), porque podemos crear bucles aparentemente infinitos que terminarán cuando ocurra una condición. Define esto dentro del bloque del ciclo: </p><pre><code class="language-C">int i = 0; 
while (1) { 
  /* haz algo */ 
  i++; 
  if ( i == 10) 
    break; 
}</code></pre><p>Es bastante común tener este tipo de bucles en C.</p><!--kg-card-begin: html--><h2 id="arreglos">Arréglos</h2><!--kg-card-end: html--><p>Un arréglo o array es una variable que almacena múltiples valores.</p><p>Todo valor en el array (en C), debe tener el mismo <strong>tipo (type)</strong>. Esto significa que tendrás arreglos de valores <code>int</code>, arreglos con valores <code>double</code>, y más.</p><p>Puedes definir un array con valores <code>int</code> así: </p><p><code>int precios[5];</code></p><p>Siempre debes especificar el tamaño del array. C no provee arreglos dinámicos listos para usar. (tienes que usar una estructura de datos como una lista enlazada para hacer eso).</p><p>Puedes usar constantes para definir el tamaño: </p><pre><code class="language-C">const int TAMANO = 5; 
int precios[TAMANO];</code></pre><p>Puedes inicializar un array al momento de su definición así: </p><pre><code class="language-C">int precios[5] = {1, 2, 3, 4, 5 };</code></pre><p>También puedes asignar valores después de su definición, de esta forma: </p><pre><code class="language-C">int precios[5]; 
precios[0] = 1; 
precios[1] = 2; 
precios[2] = 3; 
precios[3] = 4; 
precios[4] = 5;</code></pre><p>O de forma más práctica usando un ciclo: </p><pre><code class="language-C">int precios[5]; 
for (int i = 0; i&lt;5; i++) { 
  precios[i] = i + 1; 
}</code></pre><p>Puedes referenciar el item de un array usando paréntesis cuadrados después del nombre de la variable array, agregando un entero para determinar el valor del índice, así: </p><pre><code class="language-C">precios[0]; /* valor del elemento del array: 1 */ 
precios[1]; /* valor del elemento del array: 2 */</code></pre><p>Los índices de un array parten desde <code>0</code>, por lo que un array con 5 elementos, como el arreglo <code>precios</code> de más arriba tendrá elementos que parten desde <code>precios[0]</code> hasta <code>precios[4]</code>.</p><p>La parte interesante sobre los arreglos en C es que todos los elementos del array son guardados secuencialmente, uno justamente después de otro. No es algo que suceda normalmente en lenguajes de programación de más alto nivel.</p><p>Otra cosa interesante es que: el nombre de variable <code>precios</code> del array en el ejemplo anterior, es un <strong>puntero </strong>al primer elemento del array. Y como tal, se puede usar como un puntero normal.</p><p>Veremos pronto los punteros.</p><!--kg-card-begin: html--><h2 id="strings">Strings</h2><!--kg-card-end: html--><p>En C, los strings (cadenas de texto) son un tipo especial de array: un string es un array de valores <code>char</code>:</p><pre><code class="language-C">char name[6];</code></pre><p>Introduje el tipo <code>char</code> cuando toccamos el tema de los tipos, este se usa comúnmente para almacenar letras de la tabla ASCII.</p><pre><code class="language-C">char name[6] = { "M","a","u","r","o"};</code></pre><p>O de forma más conveniente con una cadena de texto literal (también llamada constante string), una secuencia de caracteres entre comillas dobles:</p><pre><code class="language-C">char name[6] = "Mauro"‌</code></pre><p>Puedes imprimir un string vía <code>printf()</code> usando <code>%s</code>:</p><p> <code>printf("%s", name);</code></p><p>Notaste que "Mauro" tiene en total 5 caracteres, pero definí el array con 6? ¿porqué? Esto es porque el último carácter de una cadena debe ser el valor <code>0</code>, el terminador de la cadena, y debemos dejar espacio para él.</p><p>Es importante mantener esto en mente, especialmente cuando manipulas strings.</p><p>Cuando hablamos de manipular strings, existe una librería estándar importante que provee C: <code>string.h</code>.</p><p>Esta librería es esencial porque abstrae muchos de los detalles de bajo nivel al trabajar, y provee un grupo de herramientas útiles.</p><p>Puedes cargar la librería agregando la siguiente línea de código en la parte superior de tu programa:</p><pre><code class="language-C">#include &lt;string.h&gt;</code></pre><p>Una vez que haces esto, tienes acceso a:</p><ul><li><code>strcpy()</code> para copiar un string sobre otro string</li><li><code>strcat()</code> para anexar un string a otro string</li><li><code>strcmp()</code> para comparar igualdad entre dos strings</li><li><code>strncpm()</code> para comparar los primeros <code>n</code> caracteres de dos strings</li><li><code>strlen()</code> para calcular el largo de un string</li></ul><p>Y muchos más</p><!--kg-card-begin: html--><h2 id="punteros">Punteros</h2><!--kg-card-end: html--><p>Los punteros son una de las partes más confusas/desafiantes de C, en mi opinión. Especialmente si eres nuevo en los lenguajes de programación, pero también si vienes de lenguajes de programación de alto nivel como Python o JavaScript.</p><p>En esta sección quiero introducirlos de la forma más sencilla, pero completa posible.</p><p>Un puntero es la dirección de un bloque de memoria que contiene una variable.</p><p>Cuando declaras un número entero como este:</p><pre><code class="language-C">  int edad = 37;</code></pre><p>Podemos usar el operador <code>&amp;</code> para obtener el valor de la dirección en memoria de la variable: </p><pre><code class="language-C">printf("%p", &amp;edad ); /* 0x7ffe3425bcac */</code></pre><p>Usé el formato <code>%p</code> especificado en <code>printf()</code> para imprimir el valor de la dirección.</p><p>Podemos asignar la dirección a una variable: </p><p><code>int *direccion = &amp;edad;</code></p><p>Usando <code>int *direccion</code> en la declaración, no estamos declarando una variable tipo entero, sino el <strong>puntero a un entero</strong>. </p><p>Podemos usar el operador de puntero <code>*</code> para obtener el valor de una variable a la que apunta una dirección: </p><pre><code class="language-C">int edad = 37; 
int *direccion = &amp;edad; 
printf("%u", *direccion); /* 37 */</code></pre><p>Esta vez estamos usando el operador de puntero otra vez, pero como no es una declaración, esta vez significa "El valor de la variable a la que apunta el puntero".</p><p>En este ejemplo, nosotros declaramos una variable <code>edad</code> y usamos un puntero para inicializar el valor: </p><pre><code class="language-C">int edad; 
int *direccion = &amp;edad; 
*direccion = 37; 
printf("%u"; *direccion);</code></pre><p>Cuando trabajes con C, te darás cuenta que muchas cosas están construidas sobre este simple concepto. Así que debes asegurarte de estar familiarizado con él, lo cual se te facilitará al realizar los ejemplos por tu cuenta.</p><p>Los punteros son una gran oportunidad de aprendizaje, porque nos obligan a pensar en las direcciones de memoria y cómo están organizados los datos.</p><p>Los arrays son un ejemplo, cuando declaras un array:</p><pre><code class="language-C">int precios[3] = { 5, 4, 3 };</code></pre><p>La variable <code>precios</code> es de hecho, un puntero al primer elemento del array. Puedes obtener el valor del primer item usando la función<code>printf()</code> &nbsp;de la siguiente forma:</p><p> <code>printf("%u", *precios); &nbsp;/* 5 */</code></p><p>Lo genial es que podemos obtener el segundo item sumando 1 al puntero <code>precios</code>: </p><p><code>printf("%u%", *(precios + 1); /* 4 */</code></p><p>De la misma forma podemos obtener los valores que siguen.</p><p>También podemos hacer muchas manipulaciones y operaciones de strings, dado que internamente, son arreglos de caracteres.</p><p>También tenemos muchas otras formas de aplicarlo, incluyendo pasar la referencia a un objeto o una función para evitar consumir más recursos al copiarlo.</p><!--kg-card-begin: html--><h2 id="funciones">Funciones</h2><!--kg-card-end: html--><p>Las funciones son formas en las que podemos estructurar nuestro código en subrutinas a las cuales podremos:</p><ol><li>Darles un nombre</li><li>Llamarlas (invocarlas) cuando lo necesitemos</li></ol><p>Al comenzar con tu primer programa ("Hola Mundo"), inmediatamente comenzaste a usar las funciones de C:</p><pre><code class="language-C">#include &lt;stdio.h&gt; 
int main(void) { 
   printf("Hola Mundo"); 
}</code></pre><p>La función <code>main()</code> es una muy importante, y es el punto de entrada a un programa en C.</p><p>Aquí hay otra función:</p><pre><code class="language-C">void hazAlgo(int valor) { 
   printf("%u", valor); 
}</code></pre><p>Las funciones tienen 4 aspectos importantes:</p><ol><li>Tienen un nombre, para que podamos invocarlas("llamarlas") en el momento que la necesitemos.</li><li>Especifican un valor de retorno</li><li>Pueden tener argumentos</li><li>Tienen un cuerpo envuelto en paréntesis de llave (<code>{}</code>)</li></ol><p>El cuerpo de la función es el conjunto de instrucciones que se ejecutará cada vez que se invoca la función.</p><p>Si la función no tiene valor de retorno, puedes usar la palabra reservada <code>void</code> antes del nombre de la función. De otra forma debes especificar el tipo de valor que retornará (<code>int</code> para enteros, <code>float</code> para decimales de punto flotante, <code>const char * </code>para un string, etc).</p><p>No puedes retornar más de un valor desde una función.</p><p>Una función puede tener argumentos. Estos son opcionales. Si no tiene argumentos, debes colocar la palabra reservada <code>void</code>, de la siguiente forma: </p><pre><code class="language-C">void hazAlgo(void) { /* ... */ }</code></pre><p>En este caso, cuando invocamos la función, la llamaremos sin elementos dentro del paréntesis:</p><pre><code class="language-C">hazAlgo();</code></pre><p>Si tenemos un parámetro, especificamos el tipo y el nombre del parámetro así:</p><pre><code class="language-C">void hazAlgo(int valor) { /* ... */ }</code></pre><p>Cuando invocamos la función, le pasaremos ese parámetro entre paréntesis de la siguiente forma: </p><pre><code class="language-C">hazAlgo(3);</code></pre><p>Podemos tener múltiples parámetros. De ser así, debemos separarlos usando una coma, tanto en la declaración como en la invocación:</p><pre><code class="language-C">void hazAlgo(int valor1, int valor2) { 
   /* ... */ 
} 
hazAlgo(3, 4);</code></pre><p>Los parámetros son pasados a la función como <strong>copias</strong>, esto significa que si modificas el <code>valor1</code>, este valor sólo se modificará localmente, es decir dentro del cuerpo de la función. El valor afuera, que fue pasado al momento de la invocación no cambiará.</p><p>Si pasas un <strong>puntero</strong> como parámetro, podrás modificar el valor de la variable, esto porque ahora podrás acceder directamente a su dirección en memoria.</p><p>No puedes definir un valor por defecto para un parámetro. C++ puede hacerlo ( y por lo tanto los programas en lenguaje Arduino), pero C no puede.</p><p>Asegúrate de definir la función antes de llamarla, o el compilador enviará un mensaje de advertencia:</p><pre><code class="language-C">➜  ~ gcc hola.c -o hola; ./hola 
hola.c:14:3: warning: implicit declaration of ç
     function 'hazAlgo' is invalid in C99 
     [-Wimplicit-function-declaration] 
   hazAlgo(3, 4); 
   ^
hola.c:17:6: error: conflicting types for
      'hazAlgo'
void hazAlgo(int valor1, char valor2) {
     ^
hola.c:13:3: note: previous implicit declaration
      is here
  hazAlgo(3, 4);
  ^
1 warning and 1 error generated.</code></pre><p>Cómo he mencionado anteriormente la alerta que hemos recibido tiene que ver con el orden.</p><p>El error se trata de otra cosa relacionada. Ya que C no puede "ver" la declaración de la función antes de la invocación entonces debe hacer suposiciones. Y asume que la función retorna un <code>int</code>, pero la función retorna <code>void</code> y a esto se debe el error.</p><p>Si cambias la definición de la función a:</p><pre><code class="language-C">int hazAlgo(int valor1, int valor2) {
  printf("%d %d\n", valor1, valor2);
  return 1;
}
</code></pre><p>Sólo obtenemos una advertencia y no el error:</p><pre><code>➜  ~ gcc hello.c -o hello; ./hello
hello.c:14:3: warning: implicit declaration of
      function 'doSomething' is invalid in C99
      [-Wimplicit-function-declaration]
  doSomething(3, 4);
  ^
1 warning generated.</code></pre><p>En cualquier caso, asegúrate de declarar la función antes de usarla. Ya sea moviendo la función hacia arriba, o agregando el prototipo de función en un archivo de cabecera.</p><p>Dentro de una función puedes declarar variables.</p><pre><code class="language-C">void hasAlgo(int valor) { 
   int dobleValor = valor * 2; 
}</code></pre><p>Una variable es creada al momento de la invocación y se destruye cuando la función termina su ejecución, la variable no será visible desde el exterior.</p><p>Dentro de una función, puedes llamar a la función en sí misma. Esto se llama <strong>recursión</strong> y es algo que ofrece oportunidades peculiares.</p><!--kg-card-begin: html--><h2 id="entradas-y-salidas">Entradas y salidas (Input Output - IO)</h2><!--kg-card-end: html--><p>C es un lenguaje pequeño, y el "núcleo" de C no incluye funcionalidades de entrada y salida, "Input/Output" (I/O).</p><p>Por supuesto, esto no es algo único de C. Es común para el núcleo de un lenguaje ser agnóstico de I/O.</p><!--kg-card-begin: markdown--><p>En el caso de C, la librería estándar nos provee Input/Output vía un conjunto de funciones definidas en el archivo de cabecera <code>stdio.h</code></p>
<!--kg-card-end: markdown--><p>Puedes importar esta librería usando <code>include &lt;stdio.h&gt;</code> en la parte superior de tu archivo C:</p><!--kg-card-begin: markdown--><pre><code>#include &lt;stdio.h&gt;
</code></pre>
<!--kg-card-end: markdown--><p>Esta librería nos provee diversas funciones:</p><!--kg-card-begin: markdown--><ul>
<li><code>printf()</code></li>
<li><code>scanf()</code></li>
<li><code>sscanf()</code></li>
<li><code>fgets()</code></li>
<li><code>fprintf()</code></li>
</ul>
<!--kg-card-end: markdown--><p>Antes de describir qué hacen estas funciones, quiero tomarme un minuto para habler sobre los <strong>flujos I/O </strong>(I/O streams) [Flujos de entrada y salida].</p><p>Tenemos 3 tipos de flujos de E/S en C:</p><!--kg-card-begin: markdown--><ul>
<li><code>stdin</code> (standard input) [entrada estandar]</li>
<li><code>stdout</code> (standard output) [salida estandar]</li>
<li><code>stderr</code> (standar error) [error estandar]</li>
</ul>
<!--kg-card-end: markdown--><p>Con las funciones I/O siempre trabajaremos con flujos. Un flujo es una interfaz de alto nivel que representa un dispositivo o un archivo. Desde el punto de vista de C, no tenemos ninguna diferencia al leer desde un archivo o leer desde la línea de comandos: ambos son un flujo I/O en cualquier caso.</p><p>Esto es algo para tener presente.</p><!--kg-card-begin: markdown--><p>Algunas funciones están diseñadas para trabajar en un flujo específico, como <code>printf()</code>, el cual usamos para imprimir caracteres al <code>stdout</code>. Al usar su contraparte más general <code>fprintf()</code>, podemos específicar a cual flujo escribiremos.</p>
<!--kg-card-end: markdown--><p>Ya que empecé hablando de <code>printf()</code>, hagámos su introducción ahora.</p><p><code>printf()</code> es una de las primeras funciones que usarás al aprender a programar en C. </p><p>En su forma de uso más simple le pasamos una cadena de texto literal:</p><pre><code class="language-c">printf("hola!");
</code></pre><p>... y el programa mostrará en consola el contenido de la cadena de texto.</p><p>También puedes imprimir el valor de una variable. Pero es algo complicado ya que necesitas agregar un carácter especial, un carácter de relleno que cambia dependiendo del tipo de la variable. Por ejemplo, usamos <code>%d</code> para un dígito decimal entero con signo:</p><pre><code class="language-C">int edad = 37;

printf("Mi edad es %d", edad);
</code></pre><p>Podemos imprimir más de una variable usando comas:</p><pre><code class="language-C">int edad_ayer = 37;
int edad_hoy = 36;

printf("Ayer mi edad era %d y hoy es %d", edad_ayer, edad_hoy);
</code></pre><p>Hay otros especificadores de formato como <code>%d</code>:</p><ul><li><code>%c</code> para caracteres</li><li><code>%s</code> para caracteres</li><li><code>%f</code> para números de punto flotante</li><li><code>%p</code> para punteros</li></ul><p>... y varios más.</p><p>Podemos usar caracteres de escape en <code>printf()</code>, como <code>\n</code> que podemos usar para crear una nueva línea en el resultado de salida.</p><h3 id="scanf-"><strong><strong><code>scanf()</code></strong></strong></h3><p><code>printf()</code> se utiliza cómo una función de salida. Ahora quiero presentarte una función de entrada para que podamos realizar todas las acciones I/O (de entrada y salida): <code>scanf()</code>.</p><p>Esta función se utiliza para obtener un valor de parte del usuario mediante la consola.</p><p>Debemos definir una variable que tomará el valor que obtuvimos desde la entrada:</p><pre><code class="language-C">int edad;
</code></pre><p>Luego la llamamos <code>scanf()</code> pasándole 2 argumentos (el formato de la variable y la dirección de variable):</p><pre><code class="language-C">scanf("%d", &amp;edad);
</code></pre><p>Si queremos obtener un string como entrada, recuerda que el nombre de un string es un puntero a el primer carácter, por lo que no necesitas usar el carácter al inicio <code>&amp;</code>:</p><pre><code class="language-c">char nombre[20];
scanf("%s", nombre);
</code></pre><p>Aquí un pequeño programa que utiliza ambos <code>printf()</code> y <code>scanf()</code>:</p><pre><code class="language-c">#include &lt;stdio.h&gt;

int main(void) {
  char nombre[20];
  printf("Escribe tu nombre: ");
  scanf("%s", nombre);
  printf("te llamas %s", nombre);
}
</code></pre><!--kg-card-begin: html--><h2 id="scope">Alcance de las variables</h2><!--kg-card-end: html--><p>Cuando defines una variable en un programa C, dependiendo de dónde lo declares, va a tener un alcance distinto (<strong>scope</strong>).</p><p>Esto significa que estará disponible en algunos lugares pero no en otros.</p><p>La ubicación de dónde es declarada, determina los 2 tipo de variables:</p><ul><li><strong>v<strong>ariables</strong> g<strong>lobal</strong>es<strong> </strong></strong></li><li><strong><strong>variables</strong> <strong>locales</strong></strong></li></ul><p>Esta es la diferencia: una variable declarada dentro de una función es una variable local, así:</p><pre><code class="language-c">int main(void) {
  int edad = 37;
}
</code></pre><p>Las variables locales sólo son accesibles desde adentro de la función y cuando la función termina, dejan de existir, es decir, son liberadas de la memoria, con algunas excepciones.</p><p>Una variable definida fuera de una función se conoce como variable global cómo en el siguiente ejemplo:</p><pre><code class="language-c">int edad = 37;

int main(void) {
  /* ... */
}
</code></pre><p>Las variables globales son accesibles desde cualquier función del programa y están disponibles por toda la ejecución del programa hasta que este concluye.</p><p>Mencioné que las variables locales no están disponibles luego de finalizar la función que las contenga.</p><p>La razón de esto es que las variables locales por defecto, son declaradas en la <strong>pila </strong>(<strong>stack</strong>),<strong> </strong>a menos que las asignes manualmente al almacenamiento dinámico (<strong>heap</strong>) usando punteros. Pero entonces tendrás que administrar el uso de memoria tú mismo. </p><!--kg-card-begin: html--><h2 id="variables-estaticas">Variables estáticas</h2><!--kg-card-end: html--><p>Dentro de una función puedes inicializar una <strong>variable estática</strong> usando la palabra reservada <code>static</code>. He dicho "dentro de una función" ya que las variables globales son estáticas por defecto, así que no hay necesidad de agregar la palabra clave <code>static</code>.</p><p>¿Qué es una variable estática? Una variable estática es inicializada a <code>0</code> si no se le asigna ningún valor y retiene su valor en todas las llamadas o invocaciones de función.</p><p>Considera esta función:</p><pre><code class="language-C">int incrementarEdad() {
  int edad = 0;
  edad++;
  return edad;
}
</code></pre><p>Si llamamos <code>incrementarEdad()</code> vamos a obtener <code>1</code> cómo valor de retorno, si la seguimos invocando, simpre obtendremos <code>1</code>, debido a que <code>edad</code> es una variable local y se reinicia su valor a <code>0</code> en cada llamada o invocación.</p><p>Si cambiamos la función a:</p><pre><code class="language-C">int incrementarEdad() {
  static int edad = 0;
  edad++;
  return edad;
}
</code></pre><p>Ahora cada vez que llamemos a esta función, vamos a obtener un valor incremental:</p><pre><code class="language-C">printf("%d\n", incrementarEdad());
printf("%d\n", incrementarEdad());
printf("%d\n", incrementarEdad());
</code></pre><p>nos arrojará</p><pre><code>1
2
3
</code></pre><p>También podemos omitir la inicialización de <code>edad</code> a <code>0</code> en la línea <code>static int edad = 0</code> y sólo escribir <code>static int edad;</code> dado que las variables estáticas reciben automáticamente el valor <code>0</code> al ser creadas.</p><p>También podemos usar arreglos estáticos, en este caso cada ítem individual en el arreglo es inicializado a <code>0</code> automáticamente:</p><pre><code class="language-C">int incrementarEdad() {
  static int edades[3];
  edades[0]++;
  return edades[0];
}
</code></pre><h2 id="variables-globales"><strong>V<strong>ariables</strong> g<strong>lobal</strong>es<strong> </strong></strong></h2><p>En esta sección quiero hablar más acerca de la diferencia entre <strong>variables globales y locales</strong>. </p><p>Una <strong>variable local</strong> se define dentro de una función y sólo se encuentra disponible dentro de esa función.</p><p>Así:</p><pre><code class="language-C">#include &lt;stdio.h&gt;

int main(void) {
  char j = 0;
  j += 10;
  printf("%u", j); //10
}
</code></pre><p><code>j</code> no está disponible en cualquier lugar fuera de la función <code>main</code>.</p><p>Una <strong>variable global</strong> se define fuera de las funciones de la siguente forma:</p><pre><code class="language-C">#include &lt;stdio.h&gt;

char i = 0;

int main(void) {
  i += 10;
  printf("%u", i); //10
}
</code></pre><p>Se puede tener acceso a una variable global desde cualquier función en el programa, además no se limita a la lectura del valor que almacena sino que este valor puede ser modificado desde cualquier función.</p><p>Debido a esto, las variables globales son una de las formas en que podemos compartir los mismos datos entre funciones.</p><p>La principal diferencia con las variables locales es que el espacio de memoria que se asigna a una variable local se libera una vez que la función termina. En cambio, el espacio de memoria de las variables locales sólo es liberado cuando termina el programa.</p><!--kg-card-begin: html--><h2 id="definiciones-de-tipos">Definiciones de tipos</h2><!--kg-card-end: html--><p>En C, la palabra reservada <code>typedef</code> nos permite definir nuevos tipos de datos.</p><p>Tomando los tipos incluidos en C como base, podemos crear nuestros propios tipos de datos usando la siguiente sintaxis:</p><pre><code class="language-C">typedef existingtype NUEVOTIPO
</code></pre><p>Por convención, es común utilizar mayúsculas para definir un nuevo tipo, esto para poder distinguirlo y reconocerlo como un tipo de dato con mayor facilidad.</p><p>Por ejemplo, podemos definir un nuevo tipo de dato <code>NUMERO</code> como <code>int</code>:</p><pre><code class="language-C">typedef int NUMERO
</code></pre><p>y una vez que lo hayas hecho podrás definir variables de tipo <code>NUMERO</code>:</p><pre><code class="language-C">NUMERO uno = 1;
</code></pre><p>¿Ahora bien, te preguntarás porqué hacer esto? ¿Porque no sólo utilizar el tipo <code>int</code> en su lugar?</p><p>Bueno, <code>typedef</code> se vuelve muy útil cuando se le acompaña de dos cosas: tipos enumerados y estructuras.</p><!--kg-card-begin: html--><h2 id="tipos-enumerados">Tipos enumerados</h2><!--kg-card-end: html--><p>Usando las palabras reservadas <code>typedef</code> y podemos definir un tipo que puede tener uno u otro valor. Es uno de los más importantes usos de la palabra reservada <code>enumtypedef</code>. </p><p>Esta es la sintaxis de la declaración un tipo enumerado:</p><pre><code class="language-c">typedef enum {
  //...valores
} NOMBRETIPO;
</code></pre><p>El tipo enumerado que creemos es usualmente por convención definido en mayúsculas .</p><p>Aquí, un ejemplo sencillo:</p><pre><code class="language-c">typedef enum {
  true,
  false
} BOOLEAN;
</code></pre><p>Aunque C ya cuenta con un tipo <code>bool</code>, lo anterior nos sirve como ejemplo explicativo.</p><p>Otro ejemplo son los días de la semana como tipo de datos:</p><pre><code class="language-C">typedef enum {
  lunes,  
  martes,
  miercoles,
  jueves,
  viernes,
  sabado,
  domingo
} DIASEMANA;
</code></pre><p>Y aquí un programa simple que utiliza este tipo enumerado:</p><pre><code class="language-c">#include &lt;stdio.h&gt;

typedef enum {
  lunes,  
  martes,
  miercoles,
  jueves,
  viernes,
  sabado,
  domingo
} DIASEMANA;

int main(void) {
  DIASEMANA dia = lunes;

  if (day == lunes) {
    printf("Es lunes!"); 
  } else {
    printf("No es lunes"); 
  }
}
</code></pre><p>Internamente cada ítem en una definición de un <code>enum</code>, se empareja con un entero. Por lo que en este ejemplo <code>lunes</code> es <code>0</code>, es y <code>martes</code> es <code>1</code> así sucesivamente.</p><p>Lo que quiere decir que la condición la pudimos haber escrito así: <code>if (dia==0)</code> y no así: <code>if (dia == lunes)</code>, sin embargo, es una sintaxis más conveniente, legible y fácil de razonar para nosotros humanos usar palabras en lugar de números.</p><!--kg-card-begin: html--><h2 id="estructuras">Estructuras</h2><!--kg-card-end: html--><p>Usando la palabra reservada <code>struct</code> podemos crear estructuras de datos complejas usando los tipos básicos de C.</p><p>Una estructura es una colección de valores de tipos distintos. Los arreglos en C están limitados a un sólo tipo de datos, por lo que las estructuras pueden ser muy útiles en muchos casos.</p><p>Esta es la sintaxis para definir una estructura:</p><pre><code class="language-c">struct &lt;nombredeestructura&gt; {
  //...variables
};
</code></pre><p>Ejemplo:</p><pre><code class="language-c">struct persona {
  int edad;
  char *nombre;
};
</code></pre><p>Puedes declarar variables que sean del tipo de la estructura que has definido, al especificar el nombre de la variable luego de la llave que cierra y antes del punto y coma, así:</p><pre><code class="language-c">struct persona {
  int edad;
  char *nombre;
} flavio;
</code></pre><p>O para múltiples variables, así:</p><pre><code class="language-c">struct persona {
  int edad;
  char *nombre;
} flavio, gente[20];
</code></pre><p>En este caso declaron una sóla variable <code>flavio</code> de tipo <code>persona</code> y un arreglo <code>gente</code> de 20 personas.</p><p>También podemos declarar las variables usando esta sintaxis:</p><pre><code class="language-c">struct persona {
  int edad;
  char *nombre;
};

struct persona flavio;
</code></pre><p>Podemos inicializar una estructura en la misma línea en que hemos declarado la variable:</p><pre><code class="language-c">struct persona {
  int edad;
  char *nombre;
};

struct persona flavio = { 37, "Flavio" };
</code></pre><p>y una vez que hayamos definido una estructura, podemos tener acceso a los valores que contiene usando un punto (notació &nbsp;de punto):</p><pre><code class="language-c">struct persona {
  int edad;
  char *nombre;
};

struct persona flavio = { 37, "Flavio" };
printf("%s, edad %u", flavio.nombre, flavio.edad);
</code></pre><p>Usando el punto también podemos editar los valores:</p><pre><code class="language-c">struct persona {
  int edad;
  char *nombre;
};

struct persona flavio = { 37, "Flavio" };

flavio.edad = 38;
</code></pre><p>Las estructuras son muy útiles porque podemos moverlas de un lado a otro o pasarlas como parámetros o valores de retorno en funciones o embedir variables y cada variable tiene una etiqueta.</p><p>Es importante mencionar que las estructuras se <strong>"pasan como copia"</strong>, a menos que por supuesto pasemos tambien un puntero, en tal caso "pasa como referencia". </p><p>Al trabajar con estructuras, podemos simplificar el código usando la palabra reservada <code>typedef</code>.</p><p>Veamos un ejemplo:</p><pre><code class="language-c">typedef struct {
  int edad;
  char *nombre;
} PERSONA;
</code></pre><p>El nombre de la estructura que creamos usando <code>typedef</code> es usualmente y por convención, escrita en mayúsculas.</p><p>Ahora podemos declarar nuevas variables <code>persona</code> así:</p><pre><code class="language-c">PERSONA flavio;
</code></pre><p>y &nbsp;las podemos inicializar en la misma línea en que fueron declaradas, así:</p><pre><code class="language-c">PERSONA flavio = { 37, "Flavio" };
</code></pre><!--kg-card-begin: html--><h2 id="parametros-de-linea-de-comandos">Parámetros de línea de comandos</h2><!--kg-card-end: html--><p>En tus programas escritos en C podrías necesitar aceptar parámetros desde la línea de comandos cuando arrancas su ejecución.</p><p>Para casos de uso simples, lo único que vas a necesitar es modificar la firma de función <code>main()</code> de:</p><pre><code class="language-c">int main(void)
</code></pre><p>a:</p><pre><code class="language-c">int main (int argc, char *argv[])
</code></pre><p><code>argc</code> es un número entero que representa el número de parámetros que fueron proporcionados mediante la línea de comandos.</p><p><code>argv</code> es un arreglo de strings (cadenas de caracteres).</p><p>Al arrancar el programa se tiene acceso a los argumentos de los 2 parámetros.</p><p>Cabe mencionar que siempre habrá por lo menos un ítem en el arreglo <code>argv</code>: el nombre del programa.</p><p>Tomemos el ejemplo del compilador C que usamos para ejecutar nuestros problemas, así:</p><pre><code class="language-sh">gcc hola.c -o hola
</code></pre><p>Si este fuera nuestro programa, <code>argc</code> sería equivalente a 4 y <code>argv</code> una matriz (arreglo) que contiene</p><ul><li><code>gcc</code></li><li><code>hello.c</code></li><li><code>-o</code></li><li><code>hello</code></li></ul><p>Escribamos un programa que imprima los argumentos que recibe:</p><pre><code class="language-c">#include &lt;stdio.h&gt;

int main (int argc, char *argv[]) {
  for (int i = 0; i &lt; argc; i++) {
    printf("%s\n", argv[i]);
  }
}
</code></pre><p>Si el nombre de nuestro programa es <code>hello</code> y lo ejecutamos así: <code>./hello</code>, obtendríamos esto como salida:</p><pre><code>./hello
</code></pre><p>Si pasamos algunos parámetros aleatorios, como este: obtendríamos esta salida a la terminal:<code>./hello a b c</code></p><pre><code>./hello
a
b
c
</code></pre><p>Este sistema funciona muy bien para casos de uso simples. Para necesidades más complejas, existen paquetes de uso común como <strong><strong>getopt</strong></strong>.</p><!--kg-card-begin: html--><h2 id="archivos-de-cabecera">Archivos de cabecera</h2><!--kg-card-end: html--><p>Los programas simples se pueden poner en un solo archivo. Pero cuando tu programa crezca, será imposible mantenerlo todo en un solo archivo.</p><p>Puede mover partes de un programa a archivos independientes. A continuación, se crea un <strong><strong>archivo de </strong>cabecera</strong>.</p><p>Un archivo de cabecera se parece a un archivo C normal, excepto que termina con en <code>.h</code> lugar de <code>.c</code>. En lugar de las implementaciones de las funciones y las otras partes de un programa, contiene las <strong>d<strong>eclaraciones</strong>.</strong></p><p>Ya usaste archivos de encabezado cuando usaste la función <code>printf()</code>, o alguna otra función de E/S, y para usarlo tuviste que escribir:	</p><pre><code class="language-c">#include &lt;stdio.h&gt;
</code></pre><p></p><p><code>#include</code> es una <strong>directiva de preprocesador</strong>.</p><p>El preprocesador va y busca el archivo <code>stdio.h</code> en la biblioteca estándar porque usó corchetes alrededor de él. Para incluir tus propios archivos de encabezado, usarás comillas, como esta:</p><figure class="kg-card kg-code-card"><pre><code class="language-c">#include "hola.h"
</code></pre><figcaption>_</figcaption></figure><p>Lo anterior buscará <code>hola.h</code> en la carpeta actual.</p><p>También puedes utilizar estructura de carpetas para bibliotecas:</p><pre><code class="language-c">#include "proyecto-hola/hola.h"
</code></pre><p>Veamos un ejemplo. Este programa calcula los años transcurridos desde un año determinado:</p><pre><code class="language-c">#include &lt;stdio.h&gt;

int calcularEdad(int anio) {
  const int ANIO_ACTUAL = 2020;
  return ANIO_ACTUAL - anio;
}

int main(void) {
  printf("%u", calcularEdad(1983));
}
</code></pre><p>Supongamos que quiero mover la función <code>calcularEdad</code> a un archivo separado.</p><p>Creo un archivo:<code>calcular_edad.c</code></p><pre><code class="language-c">int calcularEdad(int anio) {
  const int ANIO_ACTUAL = 2020;
  return ANIO_ACTUAL - anio;
}
</code></pre><p>Y un archivo <code>calcular_edad.h</code> donde pongo el prototipo de la función, que es la misma que la función en el archivo con <code>.c</code>, excepto el cuerpo de la <em><em>función</em>:</em></p><pre><code class="language-c">int calculateAge(int year);
</code></pre><p>Ahora en el archivo <code>.c</code> principal podemos ir y eliminar la definición de la función <code>calculateAge()</code>, y luego podemos importar el archivo <code>calculate_age.h</code>, lo que hará que la función <code>calculateAge()</code> esté disponible:</p><pre><code class="language-c">#include &lt;stdio.h&gt;
#include "calculate_age.h"

int main(void) {
  printf("%u", calculateAge(1983));
}
</code></pre><p>No olvides que, para compilar un programa compuesto por varios archivos, debes enumerarlos todos (pasarlos como parámetros) en la línea de comandos, así:</p><pre><code class="language-sh">gcc -o main main.c calculate_age.c
</code></pre><p>Para configuraciones más complejas, es necesario un Makefile para decirle al compilador cómo compilar el programa.</p><!--kg-card-begin: html--><h2 id="preprocesador">El preprocesador</h2><!--kg-card-end: html--><p>El preprocesador es una herramienta que nos ayuda mucho a la hora de programar con C. Es parte del estándar C, al igual que el lenguaje, el compilador y la biblioteca estándar.</p><p>El preprocesador analiza nuestro programa y se asegura de que el compilador obtenga todas las cosas que necesita antes de continuar con el proceso.</p><p>¿Qué hace en la práctica?</p><p>Por ejemplo, busca todos los archivos de encabezado que se incluyen con la directiva <code>#include</code>.</p><p>También examina todas las constantes que definió usando <code>#define</code> y las sustituye por su valor real.</p><p>Eso es solo el comienzo. Mencioné esas 2 operaciones porque son las más comunes. El preprocesador puede hacer mucho más.</p><p>¿Te diste cuenta de que <code>#include</code> y <code>#define</code> tienen un <code>#</code> un al principio? Esto es común en todas las directivas del preprocesador. Si una línea comienza con <code>#</code>, el preprocesador se encarga de ello.</p><h3 id="condicionales"><strong><strong>Condicionales</strong></strong></h3><p>Una de las cosas que podemos hacer es usar condicionales para cambiar la forma en que se compilará nuestro programa, dependiendo del valor de una expresión.</p><p>Por ejemplo, podemos comprobar si la constante <code>DEBUG</code> es <code>0</code>:</p><pre><code class="language-c">#include &lt;stdio.h&gt;

const int DEBUG = 0;

int main(void) {
#if DEBUG == 0
  printf("No estoy depurando\n");
#else
  printf("Estoy depurando\n");
#endif
}
</code></pre><h3 id="constantes-simb-licas"><strong><strong>Constantes simbólicas</strong></strong></h3><p>Podemos definir una <strong><strong>constante simbólica</strong></strong>:</p><pre><code class="language-c">#define VALUE 1
#define PI 3.14
#define NAME "Flavio"
</code></pre><p>Cuando usamos NAME o PI o VALUE en nuestro programa, el preprocesador reemplaza su nombre con el valor antes de ejecutar el programa.</p><p>Las constantes simbólicas son muy útiles porque podemos dar nombres a los valores sin crear variables en el momento de la compilación.</p><h3 id="macros"><strong><strong>Macros</strong></strong></h3><p>Con <code>#define</code> también podemos definir una <strong>macro</strong>. La diferencia entre una macro y una constante simbólica es que una macro puede aceptar un argumento y normalmente contiene código, mientras que una constante simbólica es un valor:</p><pre><code class="language-c">#define POTENCIA(x) ((x) * (x))
</code></pre><p>Observe los paréntesis alrededor de los argumentos: esta es una buena práctica para evitar problemas cuando se reemplaza la macro en el proceso de pre-compilación.</p><p>Luego podemos usarlo en nuestro código de la siguiente manera:</p><pre><code class="language-c">printf("%u\n", POTENCIA(4)); //16
</code></pre><p>La gran diferencia con las funciones es que las macros no especifican el tipo de sus argumentos o valores devueltos, lo que puede ser útil en algunos casos.</p><p>Las macros, sin embargo, se limitan a definiciones de una línea.</p><h3 id="if-defined">If defined</h3><p>Podemos comprobar si se define una constante simbólica o una macro usando <code>#ifdef</code>:</p><pre><code class="language-c">#include &lt;stdio.h&gt;
#define VALOR 1

int main(void) {
#ifdef VALOR
  printf("Valor está definido\n");
#else
  printf("Valor no está definido\n");
#endif
}
</code></pre><p>También tenemos <code>#ifndev</code> comprobar lo contrario (macro no definida).</p><p>También podemos usar <code>#if defined</code> y <code>#if !defined</code> para realizar la misma tarea.</p><p>Es común envolver algún bloque de código en un bloque como este:</p><pre><code class="language-c">#if 0

#endif
</code></pre><p>para evitar temporalmente que se ejecute o para usar una constante simbólica DEBUG:</p><pre><code class="language-c">#define DEBUG 0

#if DEBUG
  //este código sólo se envía al compilador
  //si DEBUG no es igual a 0
#endif
</code></pre><h3 id="constantes-simb-licas-predefinidas-que-puedes-usar"><strong><strong>Constantes simbólicas predefinidas que puedes usar</strong></strong></h3><p>El preprocesador también define una serie de constantes simbólicas que puede utilizar, identificadas por los 2 guiones bajos que encuentras antes y después del nombre, entre las que se incluyen:</p><ul><li><code>__LINE__</code> se traduce a la línea actual en el archivo de código fuente</li><li><code>__FILE__</code> se traduce en el nombre del archivo</li><li><code>__DATE__</code> se traduce a la fecha de compilación, en el formato<code>Mmm gg aaaa</code></li><li><code>__TIME__</code> se traduce en el tiempo de compilación, en el formato <code>hh:mm:ss</code>.</li></ul><!--kg-card-begin: html--><h2 id="conclusion">Conclusión</h2><!--kg-card-end: html--><p>¡Muchas gracias por leer este manual!</p><p>Espero que te inspire a saber más sobre C.</p><p>Para obtener más tutoriales, consulte mi blog <a href="https://flaviocopes.com/">flaviocopes.com</a>.</p><p>Sígueme en Twitter <a href="https://twitter.com/flaviocopes">@flaviocopes</a>.<br></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Tutorial Vite.js – Cómo instalar y usar Vite en tus proyectos web ]]>
                </title>
                <description>
                    <![CDATA[ Vite.js es una herramienta veloz de desarrollo de proyectos web modernos. Se enfoca en la velocidad, el desempeño y mejora la experiencia del desarrollador. Vite usa las importaciones nativas ES (ECMA Script) del navegador para habilitar el soporte a navegadores modernos sin la necesidad de un proceso de compilación ("build ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/tutorial-vite-js-como-instalar-y-usar-vite-en-tus-proyectos-web/</link>
                <guid isPermaLink="false">662d57b47b1bd304018ef4ef</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                    <category>
                        <![CDATA[ vite ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Palma ]]>
                </dc:creator>
                <pubDate>Wed, 15 May 2024 07:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2024/04/getting-started-with-vite.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/get-started-with-vite/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Vite.js Tutorial – How to Install and Use Vite in Your Web Projects</a>
      </p><p>Vite.js es una herramienta veloz de desarrollo de proyectos web modernos. Se enfoca en la velocidad, el desempeño y mejora la experiencia del desarrollador.</p><p>Vite usa las importaciones nativas ES (ECMA Script) del navegador para habilitar el soporte a navegadores modernos sin la necesidad de un proceso de compilación ("build process").</p><p>Vite consta de dos partes principales:</p><ul><li>El servidor de desarrollo brinda soporte para la "sustitución de módulos en tiempo de ejecución" o bien, "Remplazo de Módulos en Caliente" (HMR - Hot Module Replacement, por sus siglas en inglés). De esta forma, cómo su nombre lo dice, actualiza los módulos de la aplicación en tiempo de ejecución. Así, que cuando se realizan cambios en el código, sólo se actualiza la parte editada, evitando recargar la aplicación completa, lo que ayuda a acortar el tiempo de desarrollo.</li><li>El comando "build" permite a los desarrolladores empaquetar su código con Rollup, que se encuentra pre-configurado para generar recursos estáticos (static assets) altamente optimizados para producción.</li></ul><h2 id="c-mo-funciona-vite-js"><strong>Cómo funciona Vite.js</strong></h2><p>Cuando se introdujeron los módulos ES en la versión ES6/ES2015, los navegadores no contaban con soporte para los módulos ES6 o bien, era el soporte era muy pobre. En la actualidad, los navegadores modernos ya brindan este soporte, lo que permite a los desarrolladores usar las declaraciones <code>import</code> y <code>export</code> de forma nativa.</p><p>En ES nativo, sin embargo, el <code>import</code> debe usar ya sea un URL relativo o absoluto ya que no es posible realizar "importaciones simples" (bare imports) de la forma:</p><pre><code class="language-js">import { algunMetodo } from 'mi-dependencia'</code></pre><p>El código anterior lanzará un error en el navegador pues no todos los navegadores tienen soporte para los módulos ES6, y usando ES6 sería necesario utilizar un "import map". Así que la cuestión ahora es, ¿cómo ayuda Vite con esto?</p><p>Vite detecta automáticamente las "importaciones simples" (bare imports) en tus archivos fuente y lleva a cabo las siguientes dos acciones:</p><ul><li>Vite pre-empaqueta los archivos fuente para acelerar la carga de la página y convierte los módulos CommonJS o UMD a módulos ESM.</li><li>Para permitirle a los navegadores importar módulos sin lanzar errores, Vite reescribirá las importaciones cómo URLs válidos como se muestra a continuación:</li></ul><pre><code>/node_modules/.vite/my-dep.js?v=f3sf2ebb</code></pre><h1 id="-por-qu-usar-vite"><strong>¿Por qué usar Vite?</strong></h1><p>Ahora que conocemos lo que es Vite y cómo funciona, te preguntarás por qué deberías usar Vite.</p><p>Hay varias razones por las cuales deberías usarlo en tus proyectos, veamos brevemente algunas de ellas.</p><h2 id="desempe-o"><strong>Desempeño</strong></h2><p>Pre-empaquetar con ESbuild de Vite es de 10 a 100 veces más rápido que otros empaquetadores JS (bundlers). Esto se debe a que al convertir los módulos CommonsJS o UMD a módulos ESM ayuda a mejorar la velocidad de carga.</p><p>De acuerdo con la documentación de Vite,</p><blockquote>"El paso de pre-empaquetado, se realiza con esbuild y hace que el tiempo de arranque en frío de Vite sea significativamente más rápido que cualquier empaquetador basado en JavaScript."</blockquote><h2 id="hot-module-replacement-hmr-"><strong>Hot Module Replacement (HMR)</strong></h2><p>Sustitución de Módulos en Tiempo de Ejecución.</p><p>Vite utiliza funcionalidades HMR para monitorear los cambios en tu aplicación, sin tener la necesidad de recargar la página completa. Con la API HMR, el navegador sólo cargará la sección modificada de la página y conservará el resto del estado de la aplicación. </p><p>No hay necesidad de configurar manualmente la API HMR en tu aplicación ya que es agregada a tu proyecto durante la instalación, si lo creaste mediante el uso de <a href="https://es.vitejs.dev/guide/">create-vite</a>.</p><p>Con el desempeño HMR puedes diseñar aplicaciones más rápidas y ligeras sin importar el número de módulos o el tamaño de tu aplicación.</p><h2 id="opciones-de-configuraci-n"><strong>Opciones de configuración</strong></h2><p>Vite permite que tengas más control de la configuración de tu proyecto al ampliar la configuración por defecto con <code>vite.config.js</code> o <code>vite.config.ts</code>. Estos archivos se encuentran en el directorio raíz de tu proyecto.</p><p>También puedes especificar distintos archivos de configuración con la opción CLI <code>--config</code> como se muestra abajo:</p><pre><code class="language-bash">vite --config my-config.js</code></pre><h1 id="lo-que-necesitar-s"><strong>Lo que necesitarás</strong></h1><p>Este es el software que debes tener instalado en tu computadora para poder crear un proyecto Vite:</p><ul><li><a href="https://nodejs.org/en/download/">Node.js versión 12.2.0</a> o superior (para ver la versión que tienes instalada en tu computadora ejecuta <strong><strong><code>node -v</code></strong></strong> en la terminal).</li><li><a href="https://www.npmjs.com/get-npm">Npm</a> / <a href="https://classic.yarnpkg.com/en/">Yarn</a></li></ul><p>Una vez que tengas estos programas instalados en tu computadora, podrás crear proyectos con Vite.</p><h1 id="c-mo-crear-un-proyecto-con-vite"><strong>Cómo crear un proyecto con Vite </strong></h1><p>Para crear una aplicación con Vite abre tu terminal o línea de comandos y navega hacia el directorio donde quieres guardar tu aplicación con Vite. Luego ejecuta el siguiente comando:</p><pre><code class="language-bash">npm create @vitejs/app my-vite-app</code></pre><p>O para versiones más recientes de Node:</p><pre><code class="language-bash">npm create vite@latest my-vite-app</code></pre><p><strong><strong>Note:</strong></strong> <strong><strong><code>my_vite_app</code></strong></strong> es el nombre de la aplicación con Vite que vamos a crear, pero puedes cambiarlo al nombre que tú prefieras. </p><p>Luego de ejecutar el comando de arriba, se te pedirá que selecciones un <code>framework</code> y una plantilla (<code>template</code> o variant). Para los propósitos de este tutorial, vamos a usar React, pero puedes elegir cualquier framework o variante con la que te sientas más familiarizado.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/04/v-edit-1.jpg" class="kg-image" alt="v-edit-1" width="600" height="400" loading="lazy"></figure><p>A continuación, ejecuta los siguientes comandos para finalizar la instalación:</p><pre><code class="language-bash">cd vite_application
npm install</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/04/v-edit-1.png" class="kg-image" alt="v-edit-1" width="600" height="400" loading="lazy"></figure><p>La instalación puede tomar varios minutos, tendrás que esperar hasta que se haya completado.</p><h1 id="c-mo-ejecutar-una-aplicaci-n-con-vite"><strong>Cómo ejecutar una aplicación con Vite</strong></h1><p>Para ejecutar una aplicación con Vite en la terminal, navega al directorio de la aplicación que hemos creado <code>cd vite-aplication</code> y luego ejecuta el comando dev para ejecutar el servidor de desarrollo:</p><pre><code class="language-bash">npm run dev</code></pre><p>Ahora abre tu navegador e ingresa a <code><a href="http://localhost:3000/">http://localhost:3000</a></code>. Deberías ver algo como lo que muestra la siguiente captura:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/04/vite-4.PNG" class="kg-image" alt="vite-4" width="600" height="400" loading="lazy"><figcaption>Aplicación de React</figcaption></figure><h1 id="estructura-de-directorios-en-proyectos-con-vite"><strong>Estructura de directorios en proyectos con Vite</strong></h1><p>Veamos cómo es que están organizados los directorios en una aplicación con Vite. También daremos un vistazo en detalle a algunos de los directorios y archivos.</p><p>Nota: Si elijes usar un framework y/o plantilla distinto, el nombre de los archivos no será el mismo. <br></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2024/05/image.png" class="kg-image" alt="image" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2024/05/image.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2024/05/image.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/size/w1600/2024/05/image.png 1600w, https://www.freecodecamp.org/espanol/news/content/images/2024/05/image.png 1659w" sizes="(min-width: 720px) 720px" width="1659" height="1280" loading="lazy"><figcaption>Estructura de directorios en aplicaciones con Vite</figcaption></figure><h3 id="el-directorio-node_modules"><strong>El directorio <strong><strong>node_modules </strong></strong></strong></h3><p>El directorio node_modules contiene todas las dependencias necesarias para la aplicación, que se encuentran especificadas en el archivo <code>package.json</code>.</p><p>Todas las dependencias configuradas en <code>package.json</code> serán descargadas al directorio node_modules una vez que hayamos ejecutado el comando <code>npm install</code>.</p><p>Al "empujar" (del inglés push) nuestro código fuente a GitHub no es necesario incluir el directorio node_modules ya que otros usuarios del código fuente pueden descargar las dependencias necesarias de la misma forma, es decir, gracias al archivo <code>package.json</code> y npm.</p><p>Puedes encontrar el archivo <code>package.json</code> en el directorio raíz de tu proyecto.</p><h3 id="el-directorio-src"><strong>El directorio <strong><strong>src</strong></strong></strong></h3><p>El directorio src es uno de los directorios con los que más vamos a interactuar al desarrollar aplicaciones con Vite. Este directorio contiene los archivos app.jsx, main.jsx, app.css e index.js.</p><p>Todos los recursos de tu aplicación como imágenes, videos y otros archivos deben estar dentro del directorio src ya que Vite lo considera como el directorio base para las URLs en index.html. &nbsp;</p><h3 id="los-archivos-app-jsx-y-main-jsx"><strong>Los archivos App.jsx y main.jsx</strong></h3><p>El archivo App.jsx es el componente base o raíz que hace la función de contenedor de todos los otros componentes utilizados en la aplicación.</p><p>El archivo main.jsx apunta al elemento con <code>id="root"</code> que se encuentra en el archivo index.html y en el cual se renderizan todos los componentes de la aplicación. </p><h3 id="index-css-y-app-css"><strong>index.css y app.css</strong></h3><p>Estos archivos contienen todos los estilos CSS que utiliza el programa. Puedes agregar tu propio archivo CSS o editar los estilos de index.css.</p><h1 id="conclusi-n"><strong>Conclusión</strong></h1><p>Hemos visto qué es Vite, cómo funciona y algunas de sus características. También aprendimos cómo crear aplicaciones usándolo. </p><p>Para modo de mejorar nuestro flujo de trabajo como desarrolladores y ser más productivos al crear aplicaciones más ligeras y veloces, es muy recomendable visitar, explorar, leer y familiarizarse con la documentación oficial de Vite. </p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como conectarse a AWS RDS desde AWS Lambda ]]>
                </title>
                <description>
                    <![CDATA[ En este artículo, vamos a aprender cómo comunicarnos con AWS RDS desde AWS Lambda. Vamos a usar AWS CDK (Cloud Development Kit), el cual es software, o marco de trabajo (del inglés framework) de código abierto, que te permite definir y crear infraestructura en la nube (cloud). AWS CDK tiene ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-conectarse-a-aws-rds-desde-aws-lambda/</link>
                <guid isPermaLink="false">655ce5b1bcc2a003e70e34eb</guid>
                
                    <category>
                        <![CDATA[ aws ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Palma ]]>
                </dc:creator>
                <pubDate>Tue, 16 Apr 2024 19:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/11/AWS-Lambda-RDS-Proxy-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/aws-lambda-rds/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Connect to AWS RDS from AWS Lambda</a>
      </p><p>En este artículo, vamos a aprender cómo comunicarnos con AWS RDS desde AWS Lambda.</p><p>Vamos a usar <code>AWS CDK</code> (Cloud Development Kit), el cual es software, o marco de trabajo (del inglés framework) de código abierto, que te permite definir y crear infraestructura en la nube (cloud).</p><p><code>AWS CDK</code> tiene soporte para muchos lenguajes de programación, incluyendo a TypeScript, Python, C#, Java y otros. Nosotros usaremos TypeScript en este tutorial.</p><p>Al desplegar usando el comando <code>cdk deploy</code>, tu código es transformado a plantillas CloudFormation y todos los recursos AWS correspondientes serán creados. Solo necesitas conocimientos básicos de CDK y TypeScript para seguir este tutorial. Claro que también necesitas una cuenta AWS para poder crear recursos AWS.</p><p>Puedes continuar aprendiendo más acerca de AWS CDK en la <a href="https://docs.aws.amazon.com/es_es/cdk/v2/guide/getting_started.html">documentación oficial</a> y también escribí <a href="https://www.cloudtechsimplified.com/the-beginners-guide-to-aws-cdk/">una guía para principiantes </a>en mi blog (en inglés).</p><h2 id="introducci-n-a-aws-lambda-y-rds"><strong>Introducción a AWS Lambda y RDS</strong></h2><p>AWS Lambda es un servicio "serverless" de cómputo por eventos que te permite ejecutar código sin la necesidad de provisionar servidores.</p><p>AWS RDS es un servicio de base de datos relacional administrada que tiene soporte para varios sistemas RDMBS (Sistema de Bases de Datos Relacionales) como MySQL, Postgres, Oracle, SQL Server entre otros. AWS se encarga de los parches y el mantenimiento a estos servidores de bases de datos.</p><h3 id="-porque-usar-rds-junto-con-lambda"><strong>¿Porque usar RDS junto con Lambda?</strong></h3><p>AWS Lambda es un servicio de cómputo y no requiere o recomienda tecnologías específicas de almacenamiento de datos para su funcionamiento. De hecho, algunas de tus funciones lambda ni siquiera van a interactuar con almacenes de datos de algún tipo. Y si necesitaras utilizar una tecnología de almacenamiento de datos, podrías utilizar cualquier base de datos de acuerdo a tus necesidades. </p><p>Sin embargo, la mayoría de las arquitecturas serverless utilizan DynamoDB como almacén de datos sólo para reducir costos y eliminar la necesidad del mantenimiento de servidores de bases de datos.</p><p>DynamoDB es grandioso y tiene sus casos de uso aplicables. Pero usarla para todos los proyectos que involucren lambda no es posible por las siguientes razones:</p><p><strong>Patrones de acceso dinámicos:</strong> Al usar DynamoDB tendrías que diseñar con anticipación tus propios patrones de consulta. Sin embargo, esto no siempre es posible dado que tu producto (y sus respectivos requerimientos) podría evolucionar en base a la retroalimentación de tu cliente.</p><p><strong>Patrones de acceso limitado:</strong> DynamoDB no te brinda flexibilidad al escribir consultas. No puedes usar la funcionalidad <code>group by</code> en tus consultas como lo harías en un RDMBS. En cambio, necesitas exportar los datos y tener algún otro sistema que provea la funcionalidad deseada, en este caso la funcionalidad <code>group by</code>.</p><p><strong>Base de datos existente:</strong> Si tienes una base de datos RDBMS no querrás migrar a DynamoDB a menos que haya una buena razón para hacerlo. Incluso si quieres usar DynamoDB necesitarías reescribir toda la capa de acceso de datos para poder usarla como remplazo de una base de datos relacional (RDBMS).</p><h3 id="ventajas-de-usar-rdbms-"><strong>Ventajas de usar RDBMS:</strong></h3><p><strong>Relaciones entre entidades: </strong>Las bases de datos relacionales (RDBMS) permiten las relaciones entre entidades. Puedes definir claves foráneas para restringir el almacenamiento de datos inválidos.</p><p><strong>Patrones de acceso:</strong> Las bases de datos relacionales te permite el uso de patrones de acceso dinámico. Una nueva entidad puede ser traída casi sin la necesidad de realizar grandes cambios a los modelos existentes. Y tiene muchas funcionalidades cómo <code>group_by</code> para que no tengas necesidad de usar sistemas externos para facilitar estas funcionalidades.</p><p><strong>Familiaridad con SQL:</strong> La mayoría de los desarrolladores están familiarizados con SQL para realizar consultas a las bases de datos y hay una gran variedad de dónde se puede seleccionar una, incluyendo Oracle, Postgres y MySQL.</p><p>Podrías elegir RDBMS si tienes los siguientes requerimientos:</p><ul><li>Tienes una base de datos RDBMS existente y te gustaría adaptar computación serverless de AWS Lambda.</li><li>Ya cuentas con patrones dinámicos de acceso y no quieres cambiar mucho tus modelos existentes.</li></ul><p>Habiendo cubierto los puntos anteriores, discutamos cómo vamos a conectarnos a RDS desde Lambda.</p><h2 id="arquitectura-del-proyecto"><strong>Arquitectura del Proyecto </strong></h2><p>En casi la totalidad de los casos, tu base de datos RDBMS será una sub-red (subnet) de la Nube Virtual Privada (VPC - Virtual Private Cloud), con la finalidad de que nadie del exterior pueda tener acceso. Dado que tu función Lambda contendrá lógica de negocios, también podría pertenecer a esta sub-red privada.</p><p>Usaremos Postgres cómo nuestra base de datos para este tutorial. Pero el proceso descrito aquí, es aplicable para cualquier base de datos relacional (MySQL, Oracle, MS SQL y otras) que podrías querer utilizar. La arquitectura será la misma.</p><p>Abajo puedes ver la arquitectura de este proyecto:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2022/11/AWS-Lambda-RDS-Latest.png" class="kg-image" alt="AWS-Lambda-RDS-Latest" width="600" height="400" loading="lazy"></figure><p>Vamos a utilizar <code>AWS CDK</code> a modo de herramienta de tipo "Código cómo Infraestructura" para crear recursos AWS.</p><h3 id="c-mo-crear-una-nube-virtual-privada-vpc-para-alojar-nuestros-lambda-y-rdbms"><strong>Cómo crear una nube virtual privada (VPC) para alojar nuestros Lambda y RDBMS</strong></h3><p>Vamos a crear 2 subnets, una pública y otra privada. En la privada vamos a alojar nuestra base de datos Postgres.</p><pre><code class="language-typescript">const vpc = new ec2.Vpc(this, 'VpcLambda', {
      maxAzs: 2,
      subnetConfiguration: [
        {
          cidrMask: 24,
          name: 'privatelambda',
          subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
        },
        {
          cidrMask: 24,
          name: 'public',
          subnetType: ec2.SubnetType.PUBLIC,
        },
      ],
    });</code></pre><p>Cuando creas una sub-red de tipo <code>PRIVATE_WITH_EGRESS</code> usando AWS CDK también creará un NAT Gateway (NAT: Network Access Translation, Gateway puerta de acceso o enlace) y la colocará en la sub-red pública.</p><p>El propósito de NAT Gateway es permitir sólo las conexiones de salida desde tu subnet privada hacia el internet. Nadie podrá iniciar conexiones con tu subnet privada desde el internet público.</p><h3 id="-por-qu-usar-nat-gateway-para-la-conectividad-con-internet"><strong>¿Por qué usar NAT Gateway para la conectividad con internet?</strong></h3><p>Podrías estarte preguntando por qué es necesario una conexión a internet, si tenemos ambos servicios, Lambda y la base de datos RDS en la misma sub-red privada.</p><p>Secrets Manager es un servicio de AWS para el manejo y almacenamiento de datos secretos como contraseñas, certificados, etc. La contraseña para conectarse a la base de datos se encuentra almacenada en <code>secrets manager</code> y es accesible desde un endpoint (punto de acceso) público. &nbsp;</p><p>Puedes usar ya sea <code>NAT Gateway</code> para tener acceso al endpoint público del servicio de <code>secrets manager</code> o puedes crear una endpoint a modo de interfaz, para conectar con el <code>secrets manager</code> usando la Red AWS sin salir al internet público.<br><br>Ambas formas generarían un costo, pero NAT Gateway puede ser reutilizada para realizar conexiones también desde Lambda (digamos si llamas a cualquier API externa), mientras que desde un endpoint-interfaz no sería posible hacerlo de esta manera.</p><h3 id="c-mo-crear-una-instancia-de-base-de-datos-rds-para-almacenar-nuestros-datos-"><strong>Cómo crear una instancia de base de datos RDS para almacenar nuestros datos:</strong></h3><p>Para los propósitos de este tutorial vamos a usar una pequeña instancia. Pero para ambientes de producción lo más común es utilizar instancias de mayores tamaños.</p><p>Crearemos un nuevo grupo de seguridad, para de esta forma poder controlar quién tiene acceso a la instancia de la base de datos y a través de cual puerto. </p><pre><code class="language-typescript">const dbSecurityGroup = new ec2.SecurityGroup(this, 'DbSecurityGroup', {
      vpc,
    });

    const databaseName = 'cloudtechsimplified';

    const dbInstance = new rds.DatabaseInstance(this, 'Instance', {
      engine: rds.DatabaseInstanceEngine.postgres({
        version: rds.PostgresEngineVersion.VER_13,
      }),
      // optional, defaults to m5.large
      instanceType: ec2.InstanceType.of(
        ec2.InstanceClass.BURSTABLE3,
        ec2.InstanceSize.SMALL
      ),
      vpc,
      vpcSubnets: vpc.selectSubnets({
        subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
      }),
      databaseName,
      securityGroups: [dbSecurityGroup],
      credentials: rds.Credentials.fromGeneratedSecret('postgres'),
      maxAllocatedStorage: 200,
    });</code></pre><p>El código <code>CDK</code> de arriba creará una instancia de la base de datos y la colocará en la subnet privada que ya hemos creado en la sección anterior.</p><p>El método <code>fromGeneratedSecret</code> creará el secreto en el servicio secrets manager pasándole el nombre de usuario como parámetro. Queremos que el nombre de usuario sea <code>Postgres</code>, por lo que será el valor que pasaremos.<br><br>Y finalmente, vamos a asignar un espacio de 200GB de almacenamiento para la base de datos.</p><h3 id="c-mo-configurar-las-propiedades-de-la-funci-n-lambda"><strong>Cómo configurar las propiedades de la función Lambda</strong></h3><p>Usaremos Node 16 para escribir y empaquetar nuestra función Lambda, y abajo te muestro las propiedades para la Lambda.</p><p>Queremos que el 'timeout' sea de 3 minutos en lugar de los 3 segundos que son por defecto, y queremos asignar un espacio de 256MB para la función Lambda.</p><p>Ya que el <code>aws-sdk</code> ya viene provisto por el ambiente de ejecución de lambda, vamos a excluir la liberaría <code>aws-sdk</code> al escribir nuestra lambda.</p><p>Hemos instalado el paquete npm llamado <code>pg</code> que nos es útil para comunicarnos con la base de datos Postgres y excluimos el paquete <code>pg-native</code> puesto que no lo necesitamos.</p><pre><code class="language-typescript"> const nodeJsFunctionProps: NodejsFunctionProps = {
      bundling: {
        externalModules: [
          'aws-sdk', // Use the 'aws-sdk' available in the Lambda runtime
          'pg-native',
        ],
      },
      runtime: Runtime.NODEJS_16_X,
      timeout: Duration.minutes(3), // Default is 3 seconds
      memorySize: 256,
    };</code></pre><p>A continuación, crearemos un grupo de seguridad para la función lambda. Nuestra lambda debe contener información acerca del "endpoint", el nombre de usuario y la contraseña para que la lambda pueda conectarse a la base de datos.</p><p>Vamos a pasar estos valores en forma de variables de entorno a la función lambda.</p><pre><code class="language-typescript"> const lambdaSG = new ec2.SecurityGroup(this, 'LambdaSG', {
      vpc,
    });

    const rdsLambdaFn = new NodejsFunction(this, 'rdsLambdaFn', {
      entry: path.join(__dirname, '../src/lambdas', 'rds-lambda.ts'),
      ...nodeJsFunctionProps,
      functionName: 'rdsLambdaFn',
      environment: {
        DB_ENDPOINT_ADDRESS: dbInstance.dbInstanceEndpointAddress,
        DB_NAME: databaseName,
        DB_SECRET_ARN: dbInstance.secret?.secretFullArn || '',
      },
      vpc,
      vpcSubnets: vpc.selectSubnets({
        subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
      }),
      securityGroups: [lambdaSG],
    });</code></pre><p><strong>Nota Importante:</strong> No vamos a pasar la contraseña de la base de datos cómo variable de entorno, sino que pasaremos el ARN (Nombre de Recurso de Amazon) en su lugar y traeremos la mera contraseña de forma dinámica, (en tiempo de ejecución) desde el secrets manager al interior de Lambda para más y mejor seguridad.</p><h3 id="permisos-de-acceso-a-la-contrase-a-de-la-base-de-datos-para-lambda"><strong>Permisos de acceso a la contraseña de la base de datos para lambda </strong></h3><p>Aunque le hemos pasado el arn secreto (<code>secret arn</code>) en forma de variable de entorno, lambda debería tener los permisos necesarios para poder leer el secreto del secrets manager, en este caso la contraseña de la base de datos.</p><p>La línea de código de abajo provee de estos permisos:</p><pre><code class="language-typescript">dbInstance.secret?.grantRead(rdsLambdaFn);</code></pre><p>La línea de código CDK anterior creará un rol para la lambda con 2 permisos (<code>DescribeSecret</code> y <code>GetSecretValue</code>) para el secrets manager, para que de esta forma nuestra lambda tenga permitido obtener el valor secreto (la contraseña de la base de datos) antes de intentar comunicarse con ella.<br><br>Es posible ver lo mismo desde la consola AWS en el servicio Lambda.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-23.png" class="kg-image" alt="AWS Lambda Permissions for Secrets Manager" width="600" height="400" loading="lazy"><figcaption>Permisos de AWS Lambda para Secrets Manager</figcaption></figure><h3 id="grupo-de-seguridad-para-la-instancia-de-la-base-de-datos-rds"><strong>Grupo de seguridad para la instancia de la base de datos RDS </strong></h3><p>No queremos permitir que la conexión a la base de datos esté disponible para todos, pero sí queremos que las conexiones desde lambda sean posibles.</p><p>El siguiente código CDK agrega una regla de ingreso que permite la conectividad a la instancia RDS desde nuestra función lambda a través del puerto <code>5432</code> (el puerto para la base de datos Postgres):</p><pre><code class="language-typescript">  dbSecurityGroup.addIngressRule(
      lambdaSG,
      ec2.Port.tcp(5432),
      'Lambda to Postgres database'
    );</code></pre><h3 id="c-digo-de-la-funci-n-lambda-para-la-comunicaci-n-con-la-base-de-datos"><strong>Código de la función lambda para la comunicación con la base de datos</strong></h3><p>El código específico de la función lambda que le permite la comunicación con la base de datos es muy simple. Ya que estamos usando una base de datos Postgres, usaremos el paquete <code>pg</code> para comunicarnos con Postgres desde el ambiente <code>nodejs</code>. </p><p>Antes de iniciar la conexión a la base de datos, traeremos la cadena de texto desde el servicio <code>secrets manager</code>. Este texto secreto es una cadena de texto JSON que contiene tanto el nombre de usuario como la contraseña. Por lo que sólo necesitaremos usar <code>JSON.parse()</code> y tomar sólo la contraseña.</p><pre><code class="language-typescript">import * as AWS from 'aws-sdk';
import { Client } from 'pg';

export const handler = async (event: any, context: any): Promise&lt;any&gt; =&gt; {
  try {
    const host = process.env.DB_ENDPOINT_ADDRESS || '';
    console.log(`host:${host}`);
    const database = process.env.DB_NAME || '';
    const dbSecretArn = process.env.DB_SECRET_ARN || '';
    const secretManager = new AWS.SecretsManager({
      region: 'us-east-1',
    });
    const secretParams: AWS.SecretsManager.GetSecretValueRequest = {
      SecretId: dbSecretArn,
    };
    const dbSecret = await secretManager.getSecretValue(secretParams).promise();
    const secretString = dbSecret.SecretString || '';

    if (!secretString) {
      throw new Error('secret string is empty');
    }

    const { password } = JSON.parse(secretString);

    const client = new Client({
      user: 'postgres',
      host,
      database,
      password,
      port: 5432,
    });
    await client.connect();
    const res = await client.query('SELECT $1::text as message', [
      'Hello world!',
    ]);
    console.log(res.rows[0].message); // Hello world!
    await client.end();
  } catch (err) {
    console.log('error while trying to connect to db');
  }
};
</code></pre><p>Y finalmente, vamos a ejecutar una simple consulta select en nuestra base de datos.</p><h3 id="c-mo-probar-y-comprobar-el-proyecto"><strong>Cómo probar y comprobar el proyecto</strong></h3><p>Ahora ya podrás ingresar a tu consola AWS para la realización de pruebas. Selecciona el servicio <code>Lambda</code> y luego selecciona tu función lambda, en nuestro caso sería <code>rdsLambdaFn</code>.</p><p>Para este tutorial no necesitas preocuparte por la propiedad lambda <code>event</code> ya que no la vamos a utilizar en el código de nuestra función. Haz click en el botón de prueba "Test" y podrás ver los logs. &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/11/Lambda-perf-without-proxy.png" class="kg-image" alt="Test Lambda function" width="600" height="400" loading="lazy"><figcaption>Comprobando (Test) la función Lambda</figcaption></figure><h3 id="el-problema-de-rendimiento"><strong>El problema de rendimiento</strong></h3><p>Lambda es bien conocido por funciones cuya ejecución es de corta duración. De hecho, el límite máximo de "timeout" es 15 minutos.</p><p>Cómo puedes ver en el código de la función, estamos iniciando la conexión a la base de datos cada vez que la función lambda es invocada.</p><p>Dependiendo en el evento fuente de la lambda (digamos la fila SQS), esto podría crear conexiones a un ritmo mayor y se desconectaría al finalizar la función lambda.</p><p>Esto incrementa significativamente la carga al servidor de la base de datos RDS, lo que a su vez reduce el rendimiento. ¿Cómo arreglar este problema entonces?</p><h2 id="c-mo-usar-rds-proxy"><strong>Cómo usar RDS Proxy</strong></h2><p>Como alternativa a la creación directa de conexiones desde lambda hacia la base de datos, podemos tener una Proxy a RDS como intermediario entre lambda y la base de datos RDS. </p><p>El propósito del proxy RDS es mantener un conjunto de conexiones para que cualquier consumidor pueda conectarse al proxy y en su momento, a la base de datos. Nótese que aquí, no estaríamos creando una conexión, sólo obteniendo una conexión ya creada. </p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/11/AWS-RDS-Proxy-Logical-1.png" class="kg-image" alt="AWS-RDS-Proxy-Logical-1" width="600" height="400" loading="lazy"><figcaption>Usando la Proxy RDS con Lambda</figcaption></figure><p>Hay 2 ventajas al usar este método:</p><ol><li><strong>Reduce la carga al servidor de la base de datos</strong>: Dado que no necesitamos crear una conexión para cada invocación lambda en el servidor, la carga se reduce significativamente.</li><li><strong>Rendimiento <strong>lambda </strong>mejorado</strong>: Desde lambda, sólo estaremos recibiendo una conexión al proxy RDS y no estaremos creando una nueva conexión a la base de datos, lo que mejora el rendimiento de la función lambda.</li></ol><h3 id="cambios-requeridos-para-usar-el-rds-proxy"><strong>Cambios requeridos para usar el RDS Proxy</strong></h3><p>No necesitamos realizar grandes cambios a nuestra arquitectura ni a nuestro código. Sólo hay que hacer un par de cosas:</p><ul><li>Crear la proxy RDS y asociarle el grupo de seguridad de la base de datos que hemos creado anteriormente.</li><li>Actualizar la variable de entorno del endpoint lambda para que la función pueda conectarse al proxy RDS y no así a la base de datos RDS directamente.</li></ul><p>No es necesario cambiar el código de la función lambda.</p><h3 id="arquitectura-actualizada"><strong>Arquitectura actualizada</strong></h3><p>Abajo puedes ver el diagrama actualizado de la arquitectura.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/11/AWS-Lambda-RDS-Proxy.png" class="kg-image" alt="RDS Proxy with Lambda - Architecture" width="600" height="400" loading="lazy"><figcaption>RDS Proxy con Lambda - Arquitectura</figcaption></figure><h3 id="c-mo-crear-el-proxy-rds"><strong>Cómo crear el proxy RDS </strong></h3><p>Necesitamos crear el proxy RDS y agregar la instancia de la base de datos cómo el objetivo del proxy.</p><pre><code class="language-typescript">const dbProxy = new rds.DatabaseProxy(this, 'Proxy', {
      proxyTarget: rds.ProxyTarget.fromInstance(dbInstance),
      secrets: [dbInstance.secret!],
      securityGroups: [dbSecurityGroup],
      vpc,
      requireTLS: false,
      vpcSubnets: vpc.selectSubnets({
        subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
      }),
    });</code></pre><p>Nótese que también estamos pasando el secreto de la base de datos al proxy pues este será responsable de mantener las conexiones. Estamos usando el mismo grupo de seguridad de la base de datos, como hicimos para poder abrir el puerto 5432.</p><h3 id="c-mo-actualizar-el-endpoint-para-lambda"><strong>Cómo actualizar el endpoint para lambda</strong></h3><p>No es necesario que modifiquemos el código de la función lambda. Sólo necesitamos actualizar el endpoint que lo hemos pasado como variable de entorno.</p><pre><code class="language-typescript"> environment: {
        DB_ENDPOINT_ADDRESS: dbProxy.endpoint,
        DB_NAME: databaseName,
        DB_SECRET_ARN: dbInstance.secret?.secretFullArn || '',
      },</code></pre><p>No haremos ningún otro cambio.</p><h3 id="mejoras-de-rendimiento"><strong>Mejoras de rendimiento</strong></h3><p>Cuando realizas pruebas a tu función lambda, puedes ver que se conecta al proxy, en vez de a la instancia de la base de datos (ya que estamos imprimiendo la información del endpoint como <code>host</code>).</p><p>También debes notar que el rendimiento mejora significativamente. Antes tomaba cerca de 500ms (milisegundos), ahora sólo le toma 50ms..</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2022/11/image-22.png" class="kg-image" alt="Performance of lambda with RDS Proxy" width="600" height="400" loading="lazy"><figcaption>Rendimiento de lambda con RDS Proxy</figcaption></figure><p>Nótese que podría tomar tiempo adicional cuando se obtiene la conexión inicial del proxy RDS, pero obtener las subsecuentes conexiones, será rápido como se muestra arriba. </p><h2 id="conclusi-n"><strong>Conclusión</strong></h2><p>Espero que este tutorial te haya ayudado a aprender cómo realizar una conexión a RDS desde Lambda.</p><p>Gracias por leer hasta este punto, yo escribo acerca de AWS Lambda, Fargate, CI/CD Pipeline y Tecnologías Serverless en &nbsp;<a href="https://www.cloudtechsimplified.com/">https://www.cloudtechsimplified.com</a>. Si te interesa puedes suscribirte <a href="https://www.cloudtechsimplified.com/subscribe/">aquí</a>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Git push rama local a remota: Cómo publicar una nueva rama en git ]]>
                </title>
                <description>
                    <![CDATA[ Las ramas Git (del inglés branches) te permiten agregar nuevas características sin modificar la versión "viva" (de producción) de tu proyecto. Y si trabajas en un equipo, distintos desarrolladores podrían tener ramas independientes o únicas en las que trabajar. Al largo plazo tendrás que empujar (subir) esas ramas independientes a ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/git-push-rama-local-a-remota-como-publicar-una-nueva-rama-en-git/</link>
                <guid isPermaLink="false">6524252537996103e26caef9</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Palma ]]>
                </dc:creator>
                <pubDate>Tue, 12 Dec 2023 15:25:56 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/11/code-5290465_1920.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-push-local-branch-to-remote-how-to-publish-a-new-branch-in-git/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">Git Push Local Branch to Remote – How to Publish a New Branch in Git</a>
      </p><p>Las ramas Git (del inglés branches) te permiten agregar nuevas características sin modificar la versión "viva" (de producción) de tu proyecto. Y si trabajas en un equipo, distintos desarrolladores podrían tener ramas independientes o únicas en las que trabajar.</p><p>Al largo plazo tendrás que empujar (subir) esas ramas independientes a un servidor remoto como, por ejemplo; GitHub, GitLab, entre otros.</p><p>En este artículo te voy a mostrar cómo puedes empujar una rama Git de tu entorno local a un servidor remoto. No importa si todavía no has empujado ninguna rama, tampoco si ya has empujado solo la rama principal de tu repositorio y quieres empujar otras. Te voy a enseñar todo desde cero.</p><h2 id="como-empujar-la-rama-principal-al-remoto"><strong>Como empujar la rama principal al remoto</strong></h2><p>Si quieres empujar la rama main (principal) al servidor remoto por primera vez, necesitarás asegurarte de que hayas ejecutado antes los siguientes comandos: </p><ul><li><code>git init</code> para inicializar el repositorio local.</li><li><code>git add .</code> para agregar todos los archivos al repositorio local</li><li><code>git commit -m ‘mensaje descriptivo del commit’</code> para guardar los cambios realizados a los archivos que contiene el repositorio</li></ul><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss1-2.png" class="kg-image" alt="ss1-2" width="600" height="400" loading="lazy"></figure><p>Para empujar el repositorio "main", será necesario primero agregar el servidor remoto a Git ejecutando <code>git remote add &lt;url&gt;</code>.</p><p> Para confirmar que se ha agregado el servidor remoto, ejecuta <code>git remote -v</code>: </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss2-2.png" class="kg-image" alt="ss2-2" width="600" height="400" loading="lazy"></figure><p>Finalmente, para empujar el repo ejecuta <code>git push -u origin &lt;branch-name&gt;</code> ("main" es el nombre de la rama que yo estoy empujando). La rama principal podría ser "master" o "main" para ti, ya que antes "master" era el nombre por defecto, pero ahora es "main". &nbsp;Pero puedes ejecutar &nbsp;<code>git branch -M main</code> en caso de que se llame "master" para cambiarle el nombre a "main" si así lo prefieres.</p><p>Si has configurado Git para usar el asistente de credenciales, se te pedirá tu nombre de usuario GitHub y el PAT (del inglés, Personal Access Token): </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss3-2.png" class="kg-image" alt="ss3-2" width="600" height="400" loading="lazy"></figure><p>Así es como empujas la rama principal (main) por primera </p><h2 id="como-empujar-una-rama-nueva-al-repositorio-remoto"><strong>Como </strong>empujar una rama nueva al repositorio remoto</h2><p>Si tienes otra rama con la que has trabajado que quieres empujar al repositorio remoto, también usaras el comando <code>git push</code>, pero de manera ligeramente distinta.</p><p>Como recordatorio, para crear una nueva rama debes ejecutar <code>git branch nombre-rama</code>. Y para cambiarte a esa rama, para poder trabajar en ella, tienes que ejecutar <code>git switch branch-name</code> o <code>git checkout branch-name</code></p><p>Para empujar la rama al servidor remoto, ejecuta <code>git push -u origin &lt;branch name&gt;</code>. En mi caso, el nombre de esa rama es <code>bug-fixes</code>. Asi que ya he ejecutado <code>git push -u &nbsp;origin bug-fixes</code>:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss4-2.png" class="kg-image" alt="ss4-2" width="600" height="400" loading="lazy"></figure><p>Para confirmar que la rama ha sido empujada correctamente, ve a GitHub y haz clic en el menú colapsable que muestra la rama actual y las disponibles. Deberías ver la nueva rama ahí:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2022/09/ss5-2.png" class="kg-image" alt="ss5-2" width="600" height="400" loading="lazy"></figure><h2 id="conclusi-n">Conclusión</h2><p>Este artículo te ha mostrado como empujar una rama a un repositorio remoto. Además de eso, también vimos cómo puedes hacerlo por primera vez.</p><p>Si quieres aprender más acerca de git, revisa los otros artículos de <a href="https://www.freecodecamp.org/espanol/news/tag/git/">freeCodeCamp en español que cubren los temas de Git y GitHub</a>.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como ocultar las llaves API en aplicaciones frontend usando Netlify Functions ]]>
                </title>
                <description>
                    <![CDATA[ Netlify es una plataforma muy popular para desarrollo web que facilita la compilación, despliegue y administración de sitios web. Puedes usar Netlify como hosting para tus sitios y te ayuda a editarlos y publicar los cambios que realices. También te brinda características adicionales como seguridad, servicios de autenticación y autorización ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-ocultar-las-claves-api-en-aplicaciones-frontend-usando-netlify-functions/</link>
                <guid isPermaLink="false">64b5b77c363a37071b881189</guid>
                
                    <category>
                        <![CDATA[ api ]]>
                    </category>
                
                    <category>
                        <![CDATA[ frontend ]]>
                    </category>
                
                    <category>
                        <![CDATA[ serverless ]]>
                    </category>
                
                    <category>
                        <![CDATA[ lambda ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Palma ]]>
                </dc:creator>
                <pubDate>Fri, 24 Nov 2023 18:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/07/FCC-hide-API-keys-1.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/hide-api-keys-in-frontend-apps-using-netlify-functions/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Hide API Keys in Frontend Apps using Netlify Functions</a>
      </p><p>Netlify es una plataforma muy popular para desarrollo web que facilita la compilación, despliegue y administración de sitios web.</p><p>Puedes usar Netlify como hosting para tus sitios y te ayuda a editarlos y publicar los cambios que realices. También te brinda características adicionales como seguridad, servicios de autenticación y autorización de usuarios y más.</p><p>Esta guía se enfoca en mostrarte como configurar una función serverless en Netlify para ocultar las API keys de la aplicación del lado del cliente.</p><p>Para esta lección crearás un motor de búsqueda de imágenes y lo desplegarás en Netlify, que además realizará llamadas a la API de Pixabay usando funciones serverless.</p><p>Este es el mismo proceso para cualquier otra aplicación front-end (cliente) elaborada con JavaScript, con librerías JavaScript o frameworks JS como ReactJS, NextJS, VueJS, Angular, etc.</p><h3 id="prerrequisitos"><strong>Prerrequisitos</strong></h3><p>Para seguir los pasos en este tutorial deberás contar con lo siguiente:</p><ul><li>Una cuenta en Netlify (<a href="https://app.netlify.com/signup">regístrate aquí</a>)</li><li>Entendimiento básico de APIs RESTFUL, funciones Lambda y conceptos de asincronía (async/await).</li></ul><p>El demo terminado lo puedes encontrar en la rama principal de GitHub o en este enlace: <code>https://netlify-func-demo.netlify.app</code>.</p><h2 id="-qu-es-una-funci-n-netlify"><strong>¿Qué es una función Netlify?</strong></h2><p>Una función Netlify es una función serverless o lambda cuyo acceso es provisto por Netlify. Se usan para desplegar código serverless o lógica de "servidor" (back-end) pero sin la necesidad de realmente administrar un servidor dedicado.</p><p>El propósito de una función Netlify es manejar código con base en eventos (event-driven) y enviar solicitudes HTTP que devuelvan una respuesta en formato JSON.</p><blockquote>"Las funciones serverless, llamadas comercialmente "funciones Netlify" por ejecutarse en la plataforma de Netlify, son una manera de desplegar código del lado del servidor en forma de API endpoints" - Documentación Netlify </blockquote><p>La función accede de manera segura el entorno de las variables en segundo plano ("tras bamablinas") mediante una función lambda de Amazon Web Services (AWS).</p><p>Las credenciales secretas como los tokens de acceso o claves API que se ocultan sólo usando variables de entorno son menos seguras. Esto se debe a que pueden ser fácilmente obtenidas usando las "Developer Tools" (herramientas de desarrollo) a traves de la API "fetch request" del navegador.</p><p>Las claves API, si son interceptadas pueden ser mal usadas por actores maliciosos lo que podría afectar a tu aplicación o incrementar tus costos si esta depende de un servicio API de paga.</p><p>Otras funciones serverless utilizadas para ejecutar código sin tener que manejar servidores incluyen: las AWS Lambda Functions, Azure Functions y Google Cloud Functions. </p><h2 id="c-mo-configurar-una-aplicaci-n-cliente"><strong>Cómo configurar una aplicación cliente</strong></h2><h3 id="c-mo-clonar-la-aplicaci-n-demo"><strong>Cómo clonar la aplicación demo</strong></h3><p>Para empezar con este tutorial puedes clonar la "aplicación motor de búsqueda de fotos de stock" desde su &nbsp;<a href="https://github.com/frankiefab100/netlify-serverless-functions-demo/tree/main">repositorio GitHub</a>. Mira la previsualización en Netlify en <a href="https://netlify-func-demo.netlify.app/">https://netlify-func-demo.netlify.app</a>.</p><p>El primer paso es clonar el repositorio:</p><pre><code class="language-bash">git clone https://github.com/frankiefab100/netlify-serverless-functions-demo.git</code></pre><p>Paso siguiente, cambia (ingresa) al directorio <strong><strong>netlify-serverless-functions-demo</strong>.</strong></p><pre><code class="language-bash"> cd netlify-serverless-functions-demo</code></pre><p>Luego tendrás que instalar las dependencias.</p><pre><code class="language-bash">npm install
#OR 
yarn add</code></pre><p>Ahora ejecuta el servidor de desarrollo. Ejecuta el siguiente comando para este propósito:</p><pre><code class="language-bash">netlify dev</code></pre><p>La aplicación estará disponible en: <code>https://localhost:8888</code>.</p><p>Alternativamente puedes omitir los pasos anteriores si quieres crear la aplicación desde cero. En el próximo paso crearás una aplicación JavaScript para la búsqueda de fotos stock. </p><h3 id="c-mo-construir-la-aplicaci-n-demo-usando-javascript"><strong>Cómo construir la aplicación demo usando JavaScript</strong></h3><p>El primer paso es configurar la aplicación front-end (cliente). Abre tu editor de código favorito como, por ejemplo: VS Code.</p><p>A continuación, crea la carpeta <strong>dist</strong> y dentro crea el archivo index.html. Copia y pega ahí el siguiente código:</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
  &lt;head&gt;
    &lt;meta charset="UTF-8" /&gt;
    &lt;meta http-equiv="X-UA-Compatible" content="IE=edge" /&gt;
    &lt;meta name="viewport" content="width=device-width, initial-scale=1.0" /&gt;
    &lt;link rel="stylesheet" href="style.css" /&gt;
    &lt;title&gt;Stock Photos Search Engine&lt;/title&gt;
  &lt;/head&gt;
  &lt;body&gt;
    &lt;div class="container"&gt;
      &lt;header&gt;
        &lt;h1&gt;Search For Stock Photos&lt;/h1&gt;
        &lt;div class="search-section"&gt;
          &lt;input
            type="text"
            name="search"
            class="search"
            placeholder="Enter a keyword"
          /&gt;
          &lt;input
            id="searchBtn"
            class="search-btn"
            type="submit"
            value="Search"
          /&gt;
        &lt;/div&gt;
      &lt;/header&gt;

      &lt;div class="photo-wrapper"&gt;
        &lt;img src="" alt="" class="photo" /&gt;
      &lt;/div&gt;
    &lt;/div&gt;

    &lt;script src="./script.js" type="module"&gt;&lt;/script&gt;
  &lt;/body&gt;
&lt;/html&gt;</code></pre><p>En el mismo directorio <code>dist</code> agrega la siguiente hoja de estilos en un archivo llamado style.css:</p><pre><code class="language-css">/* dist/style.css */
* {
  box-sizing: border-box;
  margin: 0;
  padding: 0;
}

body {
  color: #222;
  font-family: "Roboto", sans-serif;
  font-size: 1rem;
  margin: 0 auto;
  width: 100vw;
  height: 100vh;
}

.container {
  display: flex;
  flex-direction: column;
  justify-content: center;
  align-items: center;
  text-align: center;
  min-height: 100vh;
  min-width: 100vw;
  width: 100%;
  height: 100%;
}

h1 {
  padding-bottom: 20px;
}

.search-section {
  display: inline;
  text-align: center;
  min-width: 310px;
}

.search,
.search-btn {
  border: none;
  border-radius: 5px;
  font-size: 1rem;
  padding: 15px;
  height: 50px;
}

.search {
  background-color: #d1f3bf;
  color: #222;
  min-width: 225px;
}

.search-btn {
  background-color: #04ab04;
  color: #f6f6f6;
  cursor: pointer;
  margin-left: 5px;
  min-width: 80px;
  transition: all 0.3s ease-in-out;
}

.search-btn:hover {
  background-color: #2dc22d;
}

.photo-wrapper {
  display: flex;
  gap: 15px;
  margin: 30px;
}

.photo-wrapper img {
  width: 200px;
}</code></pre><h2 id="crea-una-cuenta-gratuita-en-pixabay"><strong>Crea una cuenta gratuita en Pixabay </strong></h2><p>El primer paso para utilizar la <a href="https://pixabay.com/api/docs/">Pixabay API</a> es darse de alta una cuenta con tu correo electrónico.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/02/Pixabay-API-Documentation.png" class="kg-image" alt="Pixabay-API-Documentation" width="600" height="400" loading="lazy"><figcaption>Pixabay API key section</figcaption></figure><p>Como se muestra en la imagen de arriba, tus llaves API las puedes encontrar debajo de la seccion de parámetros en la <a href="https://pixabay.com/api/docs/">página oficial de documentación de Pixabay API</a>.</p><h3 id="crea-una-variable-de-entorno"><strong>Crea una variable de entorno</strong></h3><p>Las variables de entorno (comúnmente abreviadas como "env") son combinaciones pares de clave/valor que pueden afectar el comportamiento y los procesos de un sistema operativo o aplicación.</p><p>Usar variables de entorno se recomienda para configurar servicios de terceros y sus credenciales durante el desarrollo.</p><h3 id="instala-dotenv"><strong>Instala dotenv</strong></h3><p>Una vez que haya completado la creación de tu cuenta en Pixabay, abre tu terminal e instala el paquete <strong>dotenv</strong>. Esto permitirá que tu aplicación pueda leer las variables de entorno del archivo <strong>.env</strong>.</p><figure class="kg-card kg-code-card"><pre><code class="language-javascript">npm install dotenv
#O bien
yarn add -D dotenv</code></pre><figcaption>Usando tu terminal o línea de comandos</figcaption></figure><p>En el próximo paso podrás guardar la clave API en el archivo <strong>.env</strong>.</p><h3 id="crea-el-archivo-env"><strong>Crea el archivo .env</strong></h3><p>En la raíz del directorio de tu aplicación crea el archivo <strong>.env</strong> y almacena las llaves (keys) API copiadas de tu perfil Pixabay.</p><pre><code class="language-plaintext">PIXABAY_API_KEY=123456-7890</code></pre><p>Donde <code>PIXABAY_API_KEY=123456-7890</code> representa la llave y su valor asociado.</p><p><strong><strong>Not</strong>a: </strong>Reemplaza este par clave/valor con el valor apropiado.</p><h3 id="crea-el-archivo-gitignore"><strong>Crea </strong>el archivo<strong> .gitignore</strong></h3><p>Para evitar incluir archivos y valores sensibles como <code>node_modules</code> y <code>secret keys</code> &nbsp;en cada commit en repositorios públicos, crea el archivo <strong>.gitignore</strong> en la misma carpeta raíz del proyecto y agrega lo siguiente:</p><figure class="kg-card kg-code-card"><pre><code class="language-plaintext">node_modules
.env
.netlify</code></pre><figcaption>.gitignore</figcaption></figure><p>La carpeta <strong>.netlify</strong> que contiene funciones serverless compiladas y otros archivos serán excluidos cuando el proyecto se empuje a GitHub o a cualquier otro sistema de control de versiones.</p><h3 id="crea-una-funci-n-get-request"><strong>Crea una función get request</strong></h3><p>Ahora deberás añadir la lógica para realizar la petición fetch en el archivo <strong>script.js</strong>. Ajustaremos la lógica más adelante usando funciones Netlify.</p><pre><code class="language-javascript">/* dist/script.js */
const dotenv = require("dotenv").config();

const searchbar = document.querySelector(".search");
const submitBtn = document.querySelector(".search-btn");
const photoWrapper = document.querySelector(".photo-wrapper");

submitBtn.addEventListener("click", () =&gt; {
  getPhoto(searchbar.value);
  searchbar.value = "";
});

window.addEventListener("keydown", (e) =&gt; {
  if (e.keyCode === 13) {
    getPhoto(searchbar.value);
    searchbar.value = "";
  }
});

async function getPhoto(keyword) {
  const apiKey = PIXABAY_API_KEY;
  let apiURL = `https://pixabay.com/api/?key=${apiKey}&amp;q=${keyword}&amp;image_type=photo&amp;safesearch=true&amp;per_page=3`;

  try {
    const response = await fetch(apiURL, {
      method: "GET",
      headers: { accept: "application/json" },
    });
    const data = await response.json();

    let imageURL = data.hits;

    imageURL.forEach((result) =&gt; {
      let imageElement = document.createElement("img");
      imageElement.setAttribute("src", `${result.webformatURL}`);
      photoWrapper.appendChild(imageElement);
    });
  } catch (error) {
    alert(error);
  }
}</code></pre><p><strong>Nota: </strong>Como he mencionado anteriormente, si se publica este repositorio en GitHub, podremos acceder a la clave API en el "lado del cliente" desde un navegador, aunque hayamos excluido el archivo <code>.env</code>, mas adelante veremos como. </p><p>Para ilustrar esto, selecciona la rama <code>testing</code> <a href="https://github.com/frankiefab100/netlify-serverless-functions-demo/tree/testing">del repositorio de esta aplicación</a>. La <a href="https://testing--netlify-func-demo.netlify.app/">previsualización del sitio </a>mostrara los siguientes errores de referencia (Reference Errors) en la consola del navegador: </p><pre><code class="language-bash">Uncaught ReferenceError: require is not defined
Uncaught ReferenceError: require is not defined at getPhotos
Uncaught ReferenceError: process is not defined at getPhotos</code></pre><p>Esto se debe a que no hay manera de vincular con las variables de entorno especificadas en el archivo <strong>.env, </strong>ya que este no se envió en el commit al repositorio público en GitHub.</p><p>En el siguiente paso, selecciona y clona la rama <code>testing</code> en tu máquina de forma local con los siguientes comandos:</p><pre><code class="language-bash">git clone https://github.com/frankiefab100/netlify-serverless-functions-demo.git
cd netlify-serveless-functions-demo
npm install
netlify dev</code></pre><p>La aplicación estará disponible en tu navegador en la dirección <code>localhost:8888</code>.</p><p>Ahora abre las herramientas para desarrolladores (<strong>Developer Tools) </strong>o<strong> </strong>haz clic derecho y selecciona inspeccionar. O puedes presionar la tecla <strong>F12</strong>. Luego vea la pestaña <strong>Network</strong> y haz clic en la URL de la petición del archivo <code>getPhotos.js</code>. </p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--124----Copy.png" class="kg-image" alt="Screenshot--124----Copy" width="600" height="400" loading="lazy"><figcaption>Clave API mostrada en la pestaña Red (Network) en las herramientas de Desarrollo</figcaption></figure><p>Ahora deberías poder ver la clave API expuesta públicamente en la sección de encabezados de la pestaña <strong>Network</strong> donde fue devuelta con los datos de la respuesta en tu navegador.</p><p>Esto es un problema de seguridad ya que la pestaña Network en las herramientas de desarrollo típicamente permite mostrar información tal como la URL de la petición, el estado y los datos de la respuesta.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--127----Copy.png" class="kg-image" alt="Screenshot--127----Copy" width="600" height="400" loading="lazy"><figcaption>Clave de la API devuelta como dato de respuesta y expuesto en el URL de la petición</figcaption></figure><p>En la siguiente sección encontraras la manera segura de ocultas la clave API utilizando las funciones Netlify. </p><h2 id="c-mo-empezar-a-usar-netlify-functions"><strong>Cómo empezar a usar Netlify Functions</strong></h2><p>Primero, necesitarás iniciar sesión en tu terminal e instalar la <strong>Netlify CLI</strong> y <strong>Lambda</strong> como dependencias de desarrollo. Puedes hacerlo al ejecutar este comando:</p><pre><code class="language-bash">npm install -g netlify-cli netlify-lambda
#OR 
yarn add -D netlify-cli netlify-lambda --save-dev</code></pre><h3 id="agrega-los-comandos-personalizados-build-y-dev-en-package-json"><strong>Agrega los comandos personalizados build y dev en package.json</strong></h3><p>Estos comandos, crearán e iniciarán la aplicación en el servidor y también la ejecutarán en el nevegador. &nbsp;Aquí puedes ver un ejemplo de como podrías agregar este script con comandos en <strong>el archivo package.json</strong>:</p><pre><code class="language-bash">"scripts": {
   "build": "npm run-script",
   "dev": "netlify dev"
 }</code></pre><h3 id="instala-axios"><strong>Instala Axios</strong></h3><p>Usaremos el método <code>axios.get</code> porque esta función de Node difiere del método fetch en que este último está pensado para correr en el navegador.</p><p>Para instalar Axios, abre tu terminal e ingresa el comando:</p><pre><code class="language-bash">npm install axios
#OR
yarn add -D axios</code></pre><p>En este caso vamos a trabajar nuestra aplicación solo con JavaScript puro (vanilla JS), es decir sin usar librerías o marcos de trabajo para nuestro frontend, por lo que deberás importar axios de la siguiente manera: </p><pre><code class="language-javascript">const axios = require("axios");</code></pre><p>Para cuando se usan librerias como React, debes importar asi: </p><pre><code class="language-javascript">import axios from "axios";</code></pre><h3 id="crea-una-funci-n-serverless"><strong>Crea una función serverless </strong></h3><p>En la raíz del proyecto, crea una carpeta llamada <code>netlify</code> y a su vez dentro de este crea otra carpeta <code>functions</code>. En esta carpeta <code>functions</code> crea un archivo llamado <code>getPhotos.js</code>.</p><p>Crearás una función serverless en el archivo <code>getPhotos</code>. Esto ocultará efectivamente las llaves API cuando traigamos las imágenes desde la <a href="https://pixabay.com/api">API de Pixabay</a>.</p><pre><code class="language-javascript">//netlify/functions/getPhotos.js 
require("dotenv").config();

const axios = require("axios");

exports.handler = async (event, context) =&gt; {
  try {
    const { keyword } = event.queryStringParameters;
    let response = await axios.get(
      `https://pixabay.com/api/?key=${process.env.PIXABAY_API_KEY}&amp;q=${keyword}&amp;image_type=photo&amp;safesearch=true&amp;per_page=3`,
      {
        headers: { Accept: "application/json", "Accept-Encoding": "identity" },
        params: { trophies: true },
      }
    );

    let imageURL = response.data.hits;

    return {
      statusCode: 200,
      body: JSON.stringify({ imageURL }),
    };
  } catch (error) {
    return {
      statusCode: 500,
      body: JSON.stringify({ error }),
    };
  }
};</code></pre><p>Aquí la clave <code>process.env.PIXABAY_API_KEY</code> hace referencia al entorno de configuración de la clave API especificado en el archivo <code>.env</code> para el modo de desarrollo.</p><p>El parámetro <code>keyword</code> acepta una cadena de texto (string) que es accesible en la propiedad <code>queryStringParameters</code> y devuelve datos commo respuesta almacenados en la variable <code>imageURL</code>. Esta será enviada al archivo <code>script.js</code> como respuesta a la petición (veremos esto más adelante).</p><p>Si la petición GET es exitosa, devolverá una respuesta con el código (<code>statusCode</code>) 200 y el objeto JSON correspondiente. En caso de errores, recibiremos una alerta con el mensaje y código de estado.</p><p>Debido a cambios de versión, Axios podría devolver un Buffer como respuesta en tu terminal que se vera algo como esto:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/02/netlify-data.JPG" class="kg-image" alt="netlify-data" width="600" height="400" loading="lazy"><figcaption>Buffer de respuesta de Axios en la terminal</figcaption></figure><p>Para evitar esto deberás adjuntar lo siguiente a la petición GET:</p><pre><code class="language-javascript"> let response = await axios.get(
      `https://pixabay.com/api/?key=${process.env.PIXABAY_API_KEY}&amp;q=${keyword}&amp;image_type=photo&amp;safesearch=true&amp;per_page=3`,
      {
        headers: { Accept: "application/json", "Accept-Encoding": "identity" },
        params: { trophies: true },
      }
    );</code></pre><h3 id="crea-un-archivo-de-configuracion-netlify"><strong>Crea un archivo de configuracion Netlify</strong></h3><p>En la raíz del proyecto, crea el archivo <code>netlify.toml</code>. Este archivo especifica como es que Netlify construirá y desplegará tu aplicación.</p><p>Ahora, agrega la siguiente configuración en el archivo <code>netlify.toml</code>:</p><pre><code class="language-bash">[build]
  command = "npm run build"
  functions = "netlify/functions"
  publish = "dist"</code></pre><p><strong><strong>Not</strong>a<strong>:</strong></strong></p><ul><li><code>command = "npm run build"</code> ejecuta la Netlify CLI (Interfaz de Línea de Comandos) para que realice la construcción de la aplicación a partir de las funciones. &nbsp;</li><li><code>functions = "netlify/functions"</code> indica que las funciones en <code>getPhotos</code> existen en ña carpeta <code>netlify/functions</code>. </li><li><code>publish = "dist"</code> identifica <code>dist</code> como la carpeta desde donde será "servido" este archivo. </li></ul><h3 id="edita-el-archivo-script-js-con-la-url-para-las-peticiones-a-netlify-functions"><strong>Edita el archivo script.js con la URL para las peticiones a Netlify functions</strong></h3><p>Siguiente paso, edita la <code>apiURL</code> de esto:</p><pre><code class="language-javascript">let apiURL = `https://pixabay.com/api/?key=${apiKey}&amp;q=${keyword}&amp;image_type=photo&amp;safesearch=true&amp;per_page=3`;</code></pre><p>A esto (el endpoint para la petición HTTP a las Netlify Functions):</p><pre><code class="language-javascript">  let apiURL = `/.netlify/functions/getPhotos?keyword=${keyword}`;</code></pre><p>Esta función "serverless" será consultada desde el lado del cliente de tu aplicación mediante el endpoint: <code>/.netlify/functions/getPhotos</code>. Una vez que la solicitud es enviada, la función <code>getPhotos</code> será invocada desde <code>script.js</code>. </p><p>La respuesta <code>imageURL</code> obtenida de la Netlify functions <code>getPhotos</code> será pasada o enviada como el valor asignado al parámetro <code>keyword</code> en el "query string" (cadena de texto de consulta) de la función. Su contenido será recorrido mediante un ciclo for para devolver las 3 imágenes desde la API de Pixabay. </p><p>El archivo <strong>script.js</strong> debe verse así:</p><pre><code class="language-javascript">/* dist/script.js */
const searchbar = document.querySelector(".search");
const submitBtn = document.querySelector(".search-btn");
const photoWrapper = document.querySelector(".photo-wrapper");

submitBtn.addEventListener("click", () =&gt; {
  getPhoto(searchbar.value);
  searchbar.value = "";
  photoWrapper.innerHTML = "";
});

window.addEventListener("keydown", (e) =&gt; {
  if (e.keyCode === 13) {
    getPhoto(searchbar.value);
    searchbar.value = "";
    photoWrapper.innerHTML = "";
  }
});

async function getPhoto(keyword) {
  let apiURL = `/.netlify/functions/getPhotos?keyword=${keyword}`;

  try {
    const response = await fetch(apiURL, {
      method: "GET",
      headers: { accept: "application/json" },
    });
    const data = await response.json();

    for (let i = 0; i &lt; data.imageURL.length; i++) {
      let imageElement = document.createElement("img");
      imageElement.setAttribute("src", `${data.imageURL[i].webformatURL}`);
      photoWrapper.appendChild(imageElement);
    }
  } catch (error) {
    alert(error);
  }
}</code></pre><p><strong>Nota: </strong>En el código de arriba mantiene tu variable de entorno segura ya que se accede a esta desde una función serverless.</p><p><strong>Ejecuta el servidor de desarrollo</strong></p><p>Ahora, ejecuta tu aplicación con el siguiente comando: </p><pre><code class="language-bash">netlify dev</code></pre><p>Esto hará que se cargue la función <strong>getPhotos</strong> mediante <code>https://localhost:8888/.netlify/functions/getPhotos.</code></p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/02/netlify-dev-terminal.JPG" class="kg-image" alt="netlify-dev-terminal" width="600" height="400" loading="lazy"><figcaption>Resultado en terminal de netlify build</figcaption></figure><p>Luego, inicia el servidor de desarrollo y lanza la aplicación en tu navegador por defecto en &nbsp;<code>localhost:8888</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/02/netlify-success2.JPG" class="kg-image" alt="netlify-success2" width="600" height="400" loading="lazy"><figcaption>La función Netlify está ahora lista en https://localhost:8888</figcaption></figure><p>En este punto, la configuración de la función Netlify está completa y ya es posible realizar solicitudes <code>GET</code> HTTP.</p><h3 id="c-mo-realizar-solicitudes-para-traer-datos"><strong>Cómo realizar solicitudes para traer datos</strong></h3><p>Ahora que ya tienes la aplicación servida, hagamos una solicitud (fetch) para traer datos. Ingresa algún texto en el campo input y dale <strong>Enter o </strong>haz clic en el botón para traer las imágenes desde la API de Pixabay. </p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/02/Stock-Photos-Search-Engine--1-.png" class="kg-image" alt="Stock-Photos-Search-Engine--1-" width="600" height="400" loading="lazy"><figcaption>Imágenes de flores buscados dese la API de Pixabay</figcaption></figure><p>Para mayor información acerca del API de Pixabay, ve a su <a href="https://pixabay.com/api/docs">sitio oficial de documentación</a>. </p><p>El comando anterior enviará una solicitud a la función serverless y luego devolverá seis respuestas. Aquí cómo se verá la respuesta en la ventana de tu terminal:</p><blockquote>Request from ::1: GET /.netlify/functions/getPhotos?keyword=flower<br>Response with status 200 in 4895 ms<strong>.</strong></blockquote><p>También puedes utilizar las herramientas de desarrollador (<strong>Developer Tools)</strong> en la pestaña <strong>Network </strong>(Red) para validar la solicitud.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--118----Copy.png" class="kg-image" alt="Screenshot--118----Copy" width="600" height="400" loading="lazy"><figcaption>Datos de respuesta de la función serverless de la API</figcaption></figure><p>La solicitud devuelve la URL de nuestra aplicación, la función Netlify <strong>getPhotos</strong>, el script.js y las imágenes de Pixabay.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--120-.png" class="kg-image" alt="Screenshot--120-" width="600" height="400" loading="lazy"><figcaption>Respuesta de la petición realizada a la función Netlify vista en la sección de encabezado en la pestaña de Red (Network) del navegador.</figcaption></figure><h2 id="c-mo-hospedar-la-aplicaci-n-en-el-repositorio-remoto"><strong>Cómo hospedar la aplicación en el repositorio remoto</strong></h2><p>Ahora, deberías empujar tu proyecto al hosting de control de versiones GitHub.</p><pre><code class="language-javascript">git add .
git commit -m"initial commit"
git push origin -u main</code></pre><h2 id="c-mo-desplegar-la-aplicaci-n-y-la-funci-n-serverless-en-netlify"><strong>Cómo desplegar la aplicación y la función serverless en Netlify</strong></h2><p>Una vez que hayas publicado el proyecto en GitHub, inicia sesión en <a href="https://app.netlify.com/">Netlify</a> y conecta tu cuenta GitHub para dar autorización.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--130-.png" class="kg-image" alt="Screenshot--130-" width="600" height="400" loading="lazy"><figcaption>Importar un proyecto para despliegue en Netlify</figcaption></figure><p>Como se muestra en la imagen de arriba, haz clic en <code>Add New Project</code>y luego busca el repositorio de tu aplicación en la lista desplegable. Enseguida, haz clic en <code>Build Your Site</code>. Esto tomará algunos minutos en completarse. </p><p>Acabas de desplegar la aplicación usando la UI de Netlify. Ahora tu aplicación estará disponible en: <code>https://netlify-func-demo.netlify.app.</code></p><p>La URL para peticiones "fetch" (del inglés traer) debería verse como ésta: <code>https://netlify-func-demo.netlify.app/.netlify/functions/getPhotos</code>.</p><h2 id="opcional-c-mo-configurar-la-aplicaci-n-desde-el-tablero-netlify"><strong>Opcional - Cómo configurar la aplicación desde el tablero Netlify </strong></h2><p>Alternativamente, puedes configurar el comando Netlify desde el tablero (o panel de control, del inglés, Dashboard). Si estas configuraciones ya han sido especificadas en el archivo <strong>netlify.toml</strong>, se sobreescribirán cualquier configiracion correspondiente.</p><p>Primero, selecciona la configuración de la carpeta del proyecto en "Site settings". </p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/02/Site-overview-netlify-func-demo1.png" class="kg-image" alt="Site-overview-netlify-func-demo1" width="600" height="400" loading="lazy"><figcaption>Opciones de Sitio para la carpeta del proyecto en Netlify</figcaption></figure><h3 id="configura-el-comando-build-y-el-directorio-p-blico"><strong>Configura el comando Build y el directorio público </strong></h3><p>Ve a <code>Site settings</code>&gt; <code>Deploy</code> &gt; <code>Build &amp; Deploy</code>, edita los siguientes comandos y luego guarda los cambios:</p><ul><li>Commando build: <strong><strong>npm run build</strong></strong></li><li>Directorio público: <strong><strong>dist</strong></strong></li></ul><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--132-.png" class="kg-image" alt="Screenshot--132-" width="600" height="400" loading="lazy"><figcaption>Sección de Construcción y despliegue en Netlify</figcaption></figure><h3 id="configura-la-carpeta-de-las-funciones"><strong>Configura </strong>la carpeta de las funciones</h3><p>Por defecto, Netlify utiliza <code>netlify/functions</code> como el directorio en el cual encontrar las funciones a desplegar. En este caso, nuestra función serverless <code>getPhotos</code> se encuentra en la carpeta <code>netlify/funcions</code>.</p><p>Ahora configuraremos una carpeta personalizada donde Netlify puede encontrar tus funciones compiladas. Ve a <code>Site settings</code> &gt; <code>Functions</code> e ingresa la ruta la carpeta en donde se encuentran almacenadas las funciones de tu repositorio.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--131-.png" class="kg-image" alt="Screenshot--131-" width="600" height="400" loading="lazy"><figcaption>Sección de Carpeta de Funciones en Netlify</figcaption></figure><h3 id="c-mo-configurar-variables-de-entorno-para-producci-n"><strong>Cómo configurar variables de entorno para producción </strong></h3><p>En el panel de control de Netlify (Dashboard) haz clic en <code>Site settings</code> &gt; <code>Build &amp; deploy</code> &gt; <code>Environment</code>&gt; <code>Environment varibales</code> y luego configura el par clave/valor de la siguiente manera:</p><pre><code class="language-plaintext">PIXABAY_API_KEY=your-api-key-here</code></pre><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--133-.png" class="kg-image" alt="Screenshot--133-" width="600" height="400" loading="lazy"><figcaption>Sección de Variables de Entorno en Netlify</figcaption></figure><p>Haz clic en guardar, y enseguida redespliega la aplicación para que los cambios se apliquen. </p><p>Para redesplegar la aplicación en Netlify, ve a <code>Deploys</code> &gt; <code>Trigger deploy</code>. A continuación, selecciona <code>Clear cache and redeploy site</code>.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--134-.png" class="kg-image" alt="Screenshot--134-" width="600" height="400" loading="lazy"><figcaption>Ejecuta el redespliegue en la pestaña "Deploys" en Netlify</figcaption></figure><p><strong>Nota: </strong>El nombre de la variable de entorno (PIXABAY_API_KEY) debe coincidir con el que se referencia en el código en <code>getPhotos</code>.</p><p>Para una aplicación React, usa el prefijo <code>REACT_APP_</code> para que puedan ser leídas desde el archivo <code>.env</code>.</p><pre><code class="language-plaintext"> REACT_APP_PIXABAY_API_KEY=your-api-key-here</code></pre><h2 id="c-mo-inicializar-la-funci-n-serverless-desde-la-aplicaci-n-remota"><strong>Cómo inicializar la función serverless desde la aplicación remota</strong></h2><p>Para conectar la carpeta de tu proyecto a la aplicación web ya desplegada, inicia sesión en tu cuenta Netlify desde la terminal: </p><pre><code class="language-bash">netlify login</code></pre><p>A continuación, inicializa la aplicación en Netlify ejecutando el siguiente comando en tu terminal:</p><pre><code class="language-bash">netlify init</code></pre><p>Tu aplicación ahora está configurada para despliegues continuos via Netlify.</p><h2 id="c-mo-compilar-la-funci-n-serverless-de-netlify"><strong>Cómo compilar la función serverless de Netlify</strong></h2><p>Necesitas enlazar tu aplicación con el ID del sitio en Netlify antes de poder ejecutar el comando build en tu terminal. Para conectar la carpeta local de tu proyecto con el ID de tu sitio en Netlify, ingresa el siguiente comando en tu terminal: </p><pre><code class="language-bash">netlify link</code></pre><p>Luego de esto, se te pedirá que enlaces la carpeta mediante cualquiera de las siguientes formas:</p><ul><li>Búsqueda por nombre completo o parcial del sitio.</li><li>Elegir de una lista de tus sitios recientemente editados.</li><li>Ingresa el ID de tu sitio.</li></ul><p>Una vez que hayas seleccionado tu opción preferida, se habrá enlazado la carpeta de tu proyecto con el sitio hospedado en Netlify. Esto te permite ejecutar comandos con la <strong>CLI de Netlify </strong> y automáticamente desplegar el proyecto desde el repositorio cada que haya cambios en el código.</p><p>En el siguiente paso, compilarás una función serverless mientras se ejecuta en el servidor. Para correr el comando build definido en el archivo <code>netlify.toml</code>, ejecuta el siguiente comando:</p><pre><code class="language-bash">netlify build</code></pre><p>Esto a su vez, ejecutará el comando <code>npm run-script</code> como fue especificado en el <code>package.json</code>. Ahora, tu función serverless que está en la carpeta <code>netlify/functions</code> será empaquetado ¡exitosamente!</p><h2 id="c-mo-poner-a-prueba-la-aplicaci-n"><strong>Cómo poner a prueba la aplicación </strong></h2><p>Para realizar pruebas y confirmar que la función Netlify funciona correctamente, ejecuta el comando siguiente en tu terminal:</p><pre><code class="language-bash">netlify functions:serve</code></pre><p>Esto inyecta las variables de entorno de tu proyecto del archivo <strong>.env</strong> y ejecuta la función serverless..</p><h3 id="c-mo-confirmar-la-seguridad-de-la-clave-api-keys"><strong>Cómo confirmar la seguridad de la clave API Keys</strong></h3><p>Para inspeccionar tu aplicación y confirmar que las claves API se encuentran ocultas sigue los pasos a continuación:</p><p>Haz clic en la URL de tu aplicación hospedada y una vez abierta, navega a las herramientas de desarrollador (<strong>Developer Tools</strong>) presionando la tecla <strong>F12 </strong>o haciendo clic en cualquier lugar y seleccionando <strong>Inspeccionar</strong>. Navega a la pestaña de Red, donde deberías ver los datos traídos desde la API Pixabay. </p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/02/Screenshot--128-.png" class="kg-image" alt="Screenshot--128-" width="600" height="400" loading="lazy"><figcaption>Clave API ahora oculta de la vista pública usando las herramientas de desarrollador (<strong>Developer Tools).</strong>&nbsp;</figcaption></figure><p>Ahora ya has confirmado que has configurado exitosamente una función serverless y la has desplegado en Netlify.</p><h2 id="conclusi-n"><strong><strong><strong>Conclusi</strong></strong>ó<strong><strong>n</strong></strong></strong></h2><p>Este tutorial introdujo las funciones serverless, JavaScript asíncrono y conceptos de APIs RESTful.</p><p>Espero que ahora sepas cómo crear funciones serverless/lambda y mantener de manera segura cualquier valor sensible como las llaves/claves API que utiliza tu aplicación del lado del cliente. </p><p>Si te atoraste con algo, puedes tener acceso al código completo en el <a href="https://github.com/frankiefab100/netlify-serverless-functions-demo/tree/main">Repositorio en GitHub</a>.</p><p>¡Gracias por leer el artículo! Sígueme en <a href="https://twitter.com/frankiefab100">Twitter</a>.</p><h2 id="enlaces-relevantes"><strong>Enlaces relevantes</strong></h2><ul><li><a href="https://www.freecodecamp.org/espanol/news/como-alojar-repositorio-git-en-subdominio-con-netlify/">Cómo alojar un repositorio de GIT en un subdominio con Netlify</a></li><li><a href="https://www.freecodecamp.org/espanol/news/como-implementar-una-aplicacion-basada-en-react-router-en-netlify/">Cómo implementar una aplicación basada en React Router en Netlify</a></li><li><a href="https://www.freecodecamp.org/espanol/news/como-agregar-un-formulario-netlify-a-una-aplicacion-react-creada-con-create-react-app/">Cómo agregar un formulario Netlify a una aplicación React construida con create-react-app</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo migrar de Vue v.2 a Vue v.3 usando un proyecto simple como ejemplo ]]>
                </title>
                <description>
                    <![CDATA[ ¿Qué es Vue.js? Vue.js es un marco de trabajo para interfaces gráficas web (del inglés: "front-end framework") creado por Evan You. Es uno de los más poderosos y fáciles de usar, con más de 9.5 millones de descargas mensuales. En Septiembre 2020 se publicó la version nueva version Vue 3 ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/traduciendo-how-to-migrate-from-vue-v-2-to-vue-v-3-with-a-simple-example-project/</link>
                <guid isPermaLink="false">645842b7cc6454089f94b4e4</guid>
                
                    <category>
                        <![CDATA[ vuejs ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Palma ]]>
                </dc:creator>
                <pubDate>Mon, 07 Aug 2023 01:31:40 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/08/Cover_migration_vue_2_3.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/migrate-from-vue2-to-vue3-with-example-project/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Migrate from Vue v.2 to Vue v.3 with a Simple Example Project</a>
      </p><h2 id="-qu-es-vue-js">¿Qué es Vue.js?</h2><p>Vue.js es un marco de trabajo para interfaces gráficas web (del inglés: "front-end framework") creado por Evan You. Es uno de los más poderosos y fáciles de usar, con más de 9.5 millones de descargas mensuales.</p><p>En Septiembre 2020 se publicó la version nueva version Vue 3 core. Este nuevo Vue introduce increíbles nuevas características pero también algunos cambios disruptivos (que lo hace incompatible con versiones anteriores).</p><h2 id="-por-qu-deber-a-migrar-a-vue3">¿Por qué debería migrar a Vue3?</h2><p>Así cómo la industria tecnológica está en constante evolución, también así las librerías, lenguajes y marcos de trabajo (frameworks). En cada nueva versión se arreglan errores y se introducen nuevas características. Y frecuentemente con cada versión mayor, se mejora el flujo de trabajo para los desarrolladores. Las nuevas funcionalidades pueden darte la oportunidad lograr con facilidad cosas que anteriormente eran consideradas tareas tediosas.</p><p>Vue 3 aún es relativamente nuevo y no es urgente migrar todos tus proyectos, pero eventualmente llegará el momento en que Vue 2 ya no recibirá soporte. Por tal motivo, es buena idea conocer qué pasos necesitarás para poder realizar la migración de tus proyectos.</p><p>En esta guía te llevaré de la mano a través de los pasos básicos que necesitas realizar para familiarizarte y llevar a cabo una migración a Vue 3. Para lo cual crearemos un proyecto y luego lo migraremos a Vue 3.</p><p>El proyecto que vamos a elaborar es intencionalmente uno muy simple, esto para que cualquiera pueda seguir los pasos y aprender. Mientras más complejo sea tu proyecto, más cuidado querrás tener para planear y llevar a cabo la migración.</p><h2 id="introducci-n">Introducción</h2><p>La nueva versión de Vue.js sí contiene algunos cambios disruptivos, además de nuevas capacidades y características. También, hay librerías populares como Vue Router que han sido actualizadas para incluir soporte para la nueva versión de Vue.</p><p>Si ya sabes usar Vue 2, las bases son prácticamente las mismas. Pero antes que puedas migrar un proyecto a Vue 3 hay cambios que necesitas tomar en consideración.</p><p>Dependiendo del tamaño del proyecto que quieras migrar, asegúrate considerar todos los cambios que han sido introducidos en la nueva versión para que tu aplicación pueda seguir funcionando correctamente luego de la migración.</p><p>Para este tutorial, vamos a mantener las cosas sencillas y te mostraré cómo migrar un proyecto Vue.js que actualmente usa Vue 2 a través de un enlace CDN.</p><p>Estoy tomand0 este proyecto de un libro que escribí (sólo disponible en inglés) para freeCodeCamp; puedes encontrarlo <a href="https://www.freecodecamp.org/news/build-a-portfolio-with-vuejs/">aquí.</a></p><p>En dicho proyecto usamos Vue Router, por lo que en este artículo también daremos un vistazo a lo nuevo en Vue Router.</p><h2 id="lo-que-necesitas-para-seguir-esta-gu-a">Lo que necesitas para seguir esta guía</h2><p>Para seguir esta guía necesitas conocimiento básico de Vue.js y Vue Router. Sino tienes conocimientos básicos de Vue y Vue Router te sugiero que empieces aprendiendo acerca de estos temas primero. </p><h2 id="lo-que-cubriremos-en-este-art-culo">Lo que cubriremos en este artículo</h2><p>Este tutorial está organizado en 3 capítulos. Primero daremos un vistazo a los cambios en Vue.js v3.x para luego dar una breve revisión de Vue Router v4.x. Y finalmente planearemos la migración del proyecto real.</p><ul><li>un vistazo a Vue v3.x</li><li>cambios disruptivos para Vue v2.x</li><li>un vistazo a Vue Router v4.x </li><li>cambios disruptivos para Router v3.x</li><li>migración del proyecto portafolio</li><li>clonar el repositorio</li><li>actualizar los CDN scripts</li><li>actualizar la instancia Vue</li><li>actualizar la instancia Vue Router </li></ul><h2 id="un-vistazo-a-vue-v3-x">Un vistazo a Vue v3.x </h2><p>Vue 3 introduce algunas nuevas características y un montón de cambios disruptivos. Veamos cómo estos cambios afectarán a tu aplicación y considerémoslos antes de realizar la migración.</p><h3 id="vue-v3-x-cambios-disruptivos">Vue V3.x Cambios disruptivos</h3><p>En Vue 3 los cambios disruptivos básicamente caen en 7 categorías:</p><ul><li><strong>API Global</strong> (responsable del comportamiento de Vue) - es muy probable que quieras dar un vistazo a estos cambios.</li><li><strong>Directivas de templete</strong> (cambios en la forma en que funcionan las directivas "v-{directiva}") - es muy probable que quieras dar un vistazo a estos cambios. </li><li><strong>Componentes </strong>(cambios en su funcionamiento) - es muy probable que quieras dar un vistazo a estos cambios.</li><li><strong>La función de renderizado</strong> o bien "render function" (para la creación programática de elementos HTML).</li><li><strong>Elementos "custom"</strong> (elementos personalizados - informa a Vue de la creación de elementos HTML personalizados)</li><li><strong>Cambios menores</strong> (estos podrías no afectarte, pero de todas formas querrás revisarlos)</li><li><strong>APIs </strong>que han sido <strong>removidas </strong>(que ya no estarán disponibles para su uso en Vue 3)</li></ul><p>Entre todos los cambios hay algunos de ellos que son utilizados por cualquier aplicación que utilice Vue, cómo el API Global y los componentes. Así que necesitaras tomarlos en cuenta si quieres empezar a usar la nueva versión de Vue.</p><p>También vale la pena mencionar los siguientes cambios:</p><ul><li>La manera de crear aplicaciones e instancias de los componentes ha cambiado (API Global).</li><li>Siempre deberás declarar la opción "data" como una función (cambio menor).</li><li>Cambia el orden de precedencia al utilizar las directivas v-if y v-for en el mismo elemento.</li><li>Debes declarar la opción "emits" para los eventos de componentes.</li></ul><p>Para la lista completa de los cambios puedes leer la <a href="https://v3.vuejs.org/guide/migration/introduction.html#breaking-changes">documentación oficial</a> (en inglés) o el PR (Pull Request) de la &nbsp;<a href="https://vue3-spanish.netlify.app/">documentación en español</a> (en revisión para su publicación).</p><p>Demos un vistazo con mayor detalle a algunos de estos cambios.</p><h3 id="c-mo-crear-una-aplicaci-n-e-instancias-de-component-en-vue-3">Cómo crear una aplicación e instancias de component en Vue 3</h3><p>En Vue 3 ha cambiado la manera en que se crean los componentes. El "Vue app" ahora utiliza el nuevo método <code>.createApp()</code> para generar nuevas instancias de aplicación.</p><p>La aplicación Vue ahora se considera cómo el componente raíz, así que la forma de definir sus opciones de datos también ha cambiado.</p><p>El elemento HTML raíz no ha cambiado por lo que todavía encontrarás en el documento index.html algo como esto:</p><pre><code class="language-html">&lt;div id="app"&gt;&lt;/div&gt;

</code></pre><p>Dentro del documento JavaScript hay un cambio importante que necesitarás tomar en cuenta: ya no es necesario usar <code>new Vue()</code> para crear una instancia nueva de "app" pero en su lugar usarás el nuevo método llamado <code>.createApp()</code>, veamos una comparación de sintaxis:</p><pre><code class="language-js">
//Sintaxis Vue 3 

const app = Vue.createApp({
    // objecto "options" (opciones) 
})
app.mounth('#app') // Componente Raíz - Instancia Vue

//Sintaxis Vue 2 
const app = new Vue({
    // objecto "options" (opciones) 
    el: '#app'
})

</code></pre><h3 id="c-mo-definir-un-componente-vue-3">Cómo definir un componente Vue 3</h3><p>Para definir un componente en Vue 3 ya no se usa <code>Vue.component()</code>. En su lugar ahora se utiliza el componente raíz de la aplicación, así:</p><pre><code class="language-js">/* Sintaxis Vue 3 */
const app = Vue.createApp({
    // opciones aquí
})

app.component('componenet-name', {
    //código de componente aquí
})


/* Sintaxis Vue 2*/
Vue.component('component-name', {
    //código de componente aquí
})

</code></pre><h3 id="c-mo-usar-el-objeto-data-options-en-vue-3">Cómo usar el objeto "data options" en Vue 3</h3><p>Dado que la instancia principal de "app" se considera un componente raíz ya no se especifica la propiedad "data" como un objeto. Ahora necesitas definirla como una función que a su vez devuelve un objeto; como usualmente se hace en los componentes. &nbsp;</p><pre><code class="language-js">// Vue 3
const app = Vue.createApp({
    // objecto options 
    data(){
        return {
            message: 'hola mundo'
        }
    }
})
app.mounth('#app') // Componente raíz - Instancia Vue

// Sintaxis Vue 2 
const app = new Vue({
    // objecto options
    el: '#app'
    data: {
        message: 'hola mundo'
    }
})

</code></pre><h3 id="cambio-de-precedencia-para-v-if-v-for-en-vue-3">Cambio de precedencia para v-if/v-for en Vue 3</h3><p>En Vue 2 si usas ambas directivas en el mismo elemento lo que sucederá es que la directiva v-for tendrá precedencia sobre v-if. Pero en Vue 3, será siempre v-if la que tendrá precedencia. </p><p>Sin embargo, usar ambas directivas en el mismo elemento no es buena idea. Asegúrate de revisar la documentación al respecto.</p><h3 id="c-mo-usar-la-propiedad-emits-en-eventos-de-componente-en-vue-3">Cómo usar la propiedad "emits" en eventos de componente en Vue 3 </h3><p>Este es un cambio disruptivo así como una nueva característica.</p><p>De forma similar a la propiedad <code>props</code>, ahora en Vue 3 también existe la propiedad <code>emits</code> que es utilizada por el componente para declarar eventos que "emitirá" a su componente padre. </p><p>Recomiendo muchísimo el uso de esta propiedad para evitar emitir eventos duplicados en componentes que necesitan re-emitir eventos nativos como el evento "click".</p><p>Aquí un ejemplo de la documentación oficial:</p><pre><code class="language-js">&lt;template&gt;
  &lt;div&gt;
    &lt;p&gt;{{ texto }}&lt;/p&gt;
    &lt;button v-on:click="$emit('aceptado')"&gt;OK&lt;/button&gt;
  &lt;/div&gt;
&lt;/template&gt;
&lt;script&gt;
  export default {
    props: ['texto'],
    emits: ['aceptado']
  }
&lt;/script&gt;
</code></pre><p>La propiedad "emits" también acepta un objeto.</p><h2 id="resumen-vue-router-v4-x">Resumen Vue Router v4.x </h2><p>Con el nuevo lanzamiento de Vue.js también tenemos una nueva version de Vue Router. El nuevo lanzamiento v4.x contiene algunos cambios disruptivos que debes considerar si vas a migrar un proyecto a la nueva versión de Vue. </p><h3 id="cambios-disruptivos-en-vue-router-v4">Cambios disruptivos en Vue Router V4 </h3><p>Hay dos cambios disruptivos que son especialmente importantes de mencionar ya que son la base de una aplicación Vue Router, y deberás conocerlos si vas a migrar tu aplicación:</p><ul><li>La instancia Vue Router cambió</li><li>Hay una nueva "history option"</li></ul><p>La lista completa de cambios la puedes encontrar en la <a href="https://next.router.vuejs.org/guide/migration/index.html">documentación oficial</a> (sólo disponible en inglés).</p><p>Miremos a profundidad estos dos cambios.</p><h3 id="la-instancia-vue-router-4-ha-cambiado">La instancia Vue Router 4 ha cambiado</h3><p>Para crear una nueva instancia Vue Router ya no se usa la función-constructor VueRouter. En cambio se hace de la siguiente forma de acuerdo con la documentación oficial (sólo en inglés).</p><p>El código ha cambiado de esto:</p><pre><code class="language-js">// Crear la instacia router y pasar la opción `routes`(rutas)
// Es posible pasar opciones adicionales, 
//  pero mantengámoslo simple por ahora
const router = new VueRouter({
  routes // abreviatura para `routes: routes`
})

// Crear y montar (mount) la instancia raíz (root).
// Asegurárse de usar la instancia router para
// que toda la aplicación tenga "conocimiento" del router.
const app = new Vue({
  router
}).$mount('#app')

</code></pre><p>A esto:</p><pre><code class="language-js">// Crear la instacia router y pasar la opción `routes`(rutas)
// Es posible pasar opciones adicionales, 
//  pero mantengámoslo simple por ahora

const router = VueRouter.createRouter({
  history: VueRouter.createWebHashHistory(),
  routes, // abreviatura para `routes: routes`
});

// Crear y montar (mount) la instancia raíz (root).
const app = Vue.createApp({})
// Asegurárse de usar la instancia router para
// que toda la aplicación tenga "conocimiento" del router

app.use(router)

app.mount('#app')</code></pre><p>En el código anterior puedes ver que para crear una instancia Vue Router es necesario utilizar el objeto VueRouter llamando al método <code>createRouter()</code>.</p><p>También podemos ver que la propiedad history es obligatoria: <code>history: VueRouter.createWebHashHistory()</code>. Si no la defines se te generará un error por la consola.</p><p>A continuación crearás la instancia Vue usando el método <code>const app = createApp()</code> para luego llamar al método <code>.use()</code> desde app. </p><p>Finalmente podrás montar el elemento raíz en la instancia app usando <code>app.mount('#app')</code>.</p><h2 id="c-mo-migrar-un-proyecto-portafolio-de-vue-2-a-vue-3">Cómo migrar un proyecto portafolio de Vue 2 a Vue 3</h2><p>Considerando lo visto hasta ahora y luego de una cuidadosa consideración y revisión de los cambios disruptivos, intentemos actualizar un proyecto, usaremos un proyecto de portafolio.</p><p>Necesitaremos:</p><ul><li>Clonar el repo</li><li>Editar los scripts de las CDNs</li><li>Editar la instancia Vue</li><li>Editar la instancia Router</li></ul><p>Para migrar tu aplicación a Vue 3 necesitaremos editar lo siguiente:</p><ul><li>La instancia de aplicación Vue</li><li>La instancia Vue-Router</li><li>Enlaces a CDNs</li></ul><p>Vayamos paso a paso.</p><h3 id="clonar-el-repositorio-del-proyecto">Clonar el repositorio del proyecto</h3><p>Primero asegúrate de clonar el repositorio en el folder llamado "vue-folio":</p><pre><code class="language-sh">git clone https://bitbucket.org/fbhood/vue-folio/src/master/ vue-folio
</code></pre><p>Ya que nuestro proyecto utiliza CDN para cargar Vue el siguiente paso es editar los enlaces CDN.</p><h3 id="editar-los-enlaces-cdn">Editar los enlaces CDN </h3><p>En nuestro proyecto usamos Vue y Vue Router desde un CDN, por tal debemos actualizar ambos enlaces.</p><p>Abrir el archivo index.html y remplazar esta parte:</p><pre><code class="language-html">    &lt;!-- VueJS 3 versión de producción  --&gt;
    &lt;script src="https://cdn.jsdelivr.net/npm/vue@2.6.12"&gt;&lt;/script&gt;
    &lt;!-- Vue Router --&gt;
    &lt;script src="https://unpkg.com/vue-router@2.0.0/dist/vue-router.js"&gt;&lt;/script&gt;
</code></pre><p>con esto:</p><pre><code class="language-html">    &lt;!-- VueJS 3  versión de producción--&gt;
    &lt;script src="https://unpkg.com/vue@3"&gt;&lt;/script&gt;

    &lt;!-- Vue Router --&gt;
    &lt;script src="https://unpkg.com/vue-router@4"&gt;&lt;/script&gt;

</code></pre><h3 id="actualiza-el-c-digo">Actualiza el código</h3><p>Ahora si corres el proyecto con live server y abres el inspector notarás que la aplicación no se muestra y que hay un par de errores que se pueden ver en la consola. Ambos errores podrían relacionarse con Vue router:</p><pre><code class="language-js">You are running a development build of Vue.
Make sure to use the production build (*.prod.js) when deploying for production.

Uncaught TypeError: window.Vue.use is not a function
    at vue-router.js:1832
    at vue-router.js:9
    at vue-router.js:10

Uncaught ReferenceError: VueRouter is not defined
    at main.js:185
</code></pre><p>¡¿Vue router no está definido?! &nbsp;¿Porqué?</p><p>Bueno, recordemos que cuando Vue fue re-escrito sus librerías tuvieron que actualizar también su código. Así que, no olvidemos estos cambios disruptivos que en este caso, como podemos ver tienen relación con Vue router; ya que nuestra aplicación lo utiliza. </p><p>Actualicemos primero la instancia principal Vue para que utilice la nueva sintaxis. Luego veremos qué otros cambios necesitamos realizar para que Vue Router trabaje correctamente.</p><p>Actualiza este código que se encuentra en el archivo main.js, de esto:</p><pre><code class="language-js">// crear y montar una nueva instancia Vue

const app = new Vue({
    router
}).$mount('#app')

</code></pre><p>a esto:</p><pre><code class="language-js">// crear y montar una nueva instancia Vue

const app = Vue.createApp({
    router
})
app.mount('#app')
</code></pre><h3 id="cambios-en-vue-router-4">Cambios en Vue Router 4</h3><p>Anteriormente vimos la nueva sintaxis para definir el componente raíz con base en la instancia Vue, pero ahora necesitamos tomar en cuenta los cambios disruptivos en Vue router también.</p><h4 id="la-forma-de-instanciar-vue-router-ha-cambiado">La forma de instanciar Vue Router ha cambiado</h4><p>Cambió de esto:</p><pre><code class="language-js">// crear una nueva instancia VueRouter
const router = new VueRouter({
    routes
})

</code></pre><p>a esto:</p><pre><code class="language-js">// crear una nueva instancia VueRouter
const router = VueRouter.createRouter({
    // Provee una implementación de "history". Usamos "hash" por su simplicidad en este ejemplo.
    history: VueRouter.createWebHashHistory(),
    routes, // abreviación de `routes: routes`
})

</code></pre><p>El código anterior aborda dos cambios mayores: <code>new VueRouter()</code> ha sido remplazado con <code>VueRouter.createRouter()</code>, y la nueva opción <code>history</code> remplaza a la opción <code>mode</code>.</p><p>Finalmente, hagamos que nuestra aplicación sea consciente de que estamos usando Vue Router. Inyectamos la instancia del router en la instancia Vue y luego necesitaremos instruirla para que use el router utilizando el método <code>.use()</code> y pasar la instancia del router.</p><p>Cambiemos esto:</p><pre><code class="language-js">// crear y montar la instancia Vue

const app = Vue.createApp({
    router
})
app.mount('#app')</code></pre><p>a esto:</p><pre><code class="language-js">// crear y montar la instancia Vue

const app = Vue.createApp({})
app.use(router)
app.mount('#app')
</code></pre><p>Ahí lo tienes!</p><h2 id="conclusi-n">Conclusión</h2><p>No importa cuán compleja sea tu aplicación Vue, si deseas migrar a la nueva versión mayor, necesitarás un plan, leer las notas de cambios y novedades, así como revisar la lista de los cambios disruptivos para estar seguros que entiendes cuales partes podrían causar problemas.</p><p>Mientras más compleja sea la aplicación, más cuidadoso deberá ser el plan para la migración y su ejecución.</p><p>Para nuestra simple aplicación esto es todo lo que necesitamos hacer. Pero, no siempre será tan sencillo, así que prepárate anticipadamente.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo crear una aplicación Android de noticias usando React Native y Native Base ]]>
                </title>
                <description>
                    <![CDATA[ Vivimos es un mundo donde las cosas están en constante cambio. Así que si quieres mantenerte al día con todo lo que sucede, querrás también contar con una buena aplicación de noticias. Para ayudarte a crear tecnología "cool" y mantenerte al día, en esta publicación construiremos una aplicación de noticias ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-crear-una-aplicacion-android-de-noticias-usando-react-native-y-native-base/</link>
                <guid isPermaLink="false">62ca0635771a97081f0e2a51</guid>
                
                    <category>
                        <![CDATA[ android ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Palma ]]>
                </dc:creator>
                <pubDate>Thu, 18 May 2023 00:14:42 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/05/How-to-Build-a-Weather-Application-using-React--66-.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/build-an-android-news-app-with-react-native-and-native-base/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Build an Android News App with React Native and Native Base</a>
      </p><p>Vivimos es un mundo donde las cosas están en constante cambio. Así que si quieres mantenerte al día con todo lo que sucede, querrás también contar con una buena aplicación de noticias.</p><p>Para ayudarte a crear tecnología "cool" y mantenerte al día, en esta publicación construiremos una aplicación de noticias para Android usando React Native. Esta "traerá" los titulares desde distintos canales de noticias y los mostrará por categoría.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-21-210544.png" class="kg-image" alt="Screenshot-2021-08-21-210544" width="600" height="400" loading="lazy"></figure><p>Así es como lucirá nuestra aplicación cuando hayamos terminado. Entonces pongámos manos a la obra.</p><h2 id="c-mo-instalar-expo">Cómo instalar Expo</h2><p>Entonces, ¿Qué es Expo? Expo es un framework (marco de trabajo) que te ayuda a crear y desplegar una aplicación React Native con rapidez y facilidad. </p><p>¡Instalemos Expo!</p><figure class="kg-card kg-code-card"><pre><code>npm install --global expo-cli</code></pre><figcaption>Instalando Expo</figcaption></figure><p>Ejecuta este comando en tu terminal para instalar Expo CLI (Interfaz de Línea de Comandos). Aquí estamos usando el parámetro <code>--global</code> para asegurarnos que esté disponible desde cualquier directorio en nuestro ordenador.</p><p>Luego de haberlo instalado, necesitamos crear un proyecto Expo.</p><figure class="kg-card kg-code-card"><pre><code>expo init News-Application</code></pre><figcaption>Creando un proyecto Expo</figcaption></figure><p>Usa el comando anterior para inicializar el proyecto. También hará algunas preguntas, como el nombre de tu aplicación, cómo; si quieres agregar Typescript a tu proyecto o iniciar en blanco. Solo selecciona "blank" (iniciar en blanco) y presiona enter.</p><p>Después descargará todos los paquetes y dependencias en el folder.</p><p>Ahora, luego de haber terminado la descarga, entra al folder. Para empezar la aplicación escribe <strong><code>expo start</code></strong>. Esto abrirá las herramientas de desarrollo en el navegador.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-21-174505.png" class="kg-image" alt="Screenshot-2021-08-21-174505" width="600" height="400" loading="lazy"><figcaption>Expo developer tools</figcaption></figure><p>Aquí verás varias opciones como, correr la app en un dispositivo Android/emulador, o en un simulador iOS. Ejecutaremos al aplicación en el navegador web, así que dale click a la opción "Run in Web Browser" (correr en navegador web).</p><figure class="kg-card kg-code-card"><pre><code>import { StatusBar } from 'expo-status-bar';
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';

export default function App() {
  return (
    &lt;View style={styles.container}&gt;
      &lt;Text&gt;Open up App.js to start working on your app!&lt;/Text&gt;
      &lt;StatusBar style="auto" /&gt;
    &lt;/View&gt;
  );
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: '#fff',
    alignItems: 'center',
    justifyContent: 'center',
  },
});
</code></pre><figcaption>Nuestro archivo App.js</figcaption></figure><p>Este es nuestro archivo App.js, que contiene la plantilla predeterminada.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/04/Abrel-el-archivo-App.ljs-para-empezar-a-trabajar-en-tu-app--1.jpg" class="kg-image" alt="Abrel-el-archivo-App.ljs-para-empezar-a-trabajar-en-tu-app--1" width="414" height="675" loading="lazy"><figcaption>Este es nuestro resultado.</figcaption></figure><p>Ahora nuestra aplicación se está ejecutando.</p><h2 id="c-mo-crear-varias-vistas-usando-react-navigation">Cómo crear varias vistas usando React Navigation</h2><p>Ahora vamos a crear varias pantallas para nuestra aplicación. Para eso, usaremos "React Navigation". Así que vamos a instalarla.</p><p>Dirígete a <a href="https://reactnavigation.org/">https://reactnavigation.org/</a> &nbsp;y da click a "Read Docs" (leer documentación). Este enlace te llevará a la página de la documentación.</p><p>Instalemos "React Navigation" usando el siguiente comando:</p><figure class="kg-card kg-code-card"><pre><code>npm install @react-navigation/native

expo install react-native-screens react-native-safe-area-context</code></pre><figcaption>Instalando React Navigation</figcaption></figure><p>Ahora "React Navigation" ha sido instalado.</p><p>Usaremos &nbsp;<code>bottomTabNavigator</code>. Así que, desde el menú izquierdo, selecciona "API Reference", luego "Navigators" y finalmente "Bottom Tabs".</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-21-175641.png" class="kg-image" alt="Screenshot-2021-08-21-175641" width="600" height="400" loading="lazy"><figcaption>Selecciona Bottom Tabs</figcaption></figure><p>Instalemos "Bottom Tabs" usando el siguiente comando:</p><figure class="kg-card kg-code-card"><pre><code>npm install @react-navigation/bottom-tabs</code></pre><figcaption>Instalando Bottom Tabs</figcaption></figure><p>Ahora en nuestro archivo App.js, necesitamos importar Bottom Tabs para poder utilizarlo.</p><p>Lo importas así:</p><figure class="kg-card kg-code-card"><pre><code>import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
</code></pre><figcaption>Importando Bottom Tabs</figcaption></figure><p>Ahora importemos el "Tab Screens".</p><figure class="kg-card kg-code-card"><pre><code>import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { NavigationContainer } from '@react-navigation/native';
const Tab = createBottomTabNavigator();

function MyTabs() {
  return (
    &lt;Tab.Navigator&gt;
      &lt;Tab.Screen name="Home" component={HomeScreen} /&gt;
      &lt;Tab.Screen name="Settings" component={SettingsScreen} /&gt;
    &lt;/Tab.Navigator&gt;
  );
}</code></pre><figcaption>Importando el "navegador de pantallas por pestañas" - Tab Navigator Screens</figcaption></figure><p>De esta forma es que creamos las pestañas y botones de la navegación de la parte inferior de la pantalla, usando Bottom Tabs.</p><p>En nuestro caso, necesitamos hacer algo como esto:</p><pre><code>&lt;Tab.Navigator&gt;
  &lt;Tab.Screen name="All" component={All} /&gt;
  &lt;Tab.Screen name="Business" component={Business} /&gt;
  &lt;Tab.Screen name="Health" component={HealthScreen} /&gt;
  &lt;Tab.Screen name="Sports" component={SportsScreen} /&gt;
  &lt;Tab.Screen name="Tech" component={TechScreen} /&gt;
&lt;/Tab.Navigator&gt;</code></pre><p>Necesitamos crear estas pantallas para las siguientes pestañas: All news, Business News, Sports News, Health News y Tech News. También vamos a crear un componente en el proyecto para cada pantalla.</p><p>Necesitamos envolver &nbsp;<code>TabNavigtor</code> en un <code>NavigationContainer</code> así:</p><pre><code>&lt;NavigationContainer&gt;
  &lt;Tab.Navigator&gt;
    &lt;Tab.Screen name="All" component={All} /&gt;
    &lt;Tab.Screen name="Business" component={Business} /&gt;
    &lt;Tab.Screen name="Health" component={HealthScreen} /&gt;
    &lt;Tab.Screen name="Sports" component={SportsScreen} /&gt;
    &lt;Tab.Screen name="Tech" component={TechScreen} /&gt;
  &lt;/Tab.Navigator&gt;
&lt;/NavigationContainer&gt;</code></pre><p>También necesitamos importar todos estos componentes, así que los importamos en la parte superior de nuestro archivo.</p><pre><code>import All from './screens/All';
import Business from './screens/Business';
import HealthScreen from './screens/Health';
import SportsScreen from './screens/Sports';
import TechScreen from './screens/Tech';</code></pre><p>Ahora bien, si juntamos lo que hemos escrito, obtendremos el código siguiente:</p><figure class="kg-card kg-code-card"><pre><code>import React from 'react';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { NavigationContainer } from '@react-navigation/native';
import All from './screens/All';
import Business from './screens/Business';
import HealthScreen from './screens/Health';
import SportsScreen from './screens/Sports';
import TechScreen from './screens/Tech';
const Tab = createBottomTabNavigator();

export default function App() {
  return (
    &lt;NavigationContainer&gt;
      &lt;Tab.Navigator&gt;
        &lt;Tab.Screen name="All" component={All} /&gt;
        &lt;Tab.Screen name="Business" component={Business} /&gt;
        &lt;Tab.Screen name="Health" component={HealthScreen} /&gt;
        &lt;Tab.Screen name="Sports" component={SportsScreen} /&gt;
        &lt;Tab.Screen name="Tech" component={TechScreen} /&gt;
      &lt;/Tab.Navigator&gt;
    &lt;/NavigationContainer&gt;
  );
} </code></pre><figcaption>El código para las pantallas.</figcaption></figure><p>Y este sería el resultado:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-21-181356.png" class="kg-image" alt="Screenshot-2021-08-21-181356" width="600" height="400" loading="lazy"><figcaption>Nuestras cinco pantallas, a saber: All (Todo), Business (Negocios), Health (Salud), Sports (Deportes) y Tech (Tecnología)</figcaption></figure><p>Tenemos aquí cinco pantallas: All (Todo), Business (Negocios), Health (Salud), Sports (Deportes) y Tech (Tecnología).</p><p>Ahora hagamos algunos ajustes. Necesitamos cambiar los íconos para las pestañas de la parte inferior.</p><p>Para hacer esto necesitaremos recurrir al uso de una librería de íconos. También utilizaremos <em>react-native-elements.</em></p><p>Para instalar <em>react-native-elements, escribe el comando de abajo:</em></p><figure class="kg-card kg-code-card"><pre><code>npm install react-native-elements</code></pre><figcaption>Instalar React Native Elements</figcaption></figure><p>Este paquete de íconos tiene muchas opciones para elegir.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-21-193917.png" class="kg-image" alt="Screenshot-2021-08-21-193917" width="600" height="400" loading="lazy"><figcaption>Íconos disponibles en React Native Elements</figcaption></figure><p>Ahora agreguemos nuestros íconos en la navegación por pestañas inferior (Bottom Tab Navigator).</p><figure class="kg-card kg-code-card"><pre><code>&lt;Tab.Screen name="All" component={All}
          options={{
            tabBarIcon: (props) =&gt; (
              &lt;Icon type='feather' name='home' color={props.color} /&gt;
            ),
          }} /&gt;</code></pre><figcaption>Agregando un ícono para la pagina de inicio (home)</figcaption></figure><p>Aquí hemos agregado el ícono llamado "home" para la página de inicio y el tipo feather cómo valor para el atributo type.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-21-194136.png" class="kg-image" alt="Screenshot-2021-08-21-194136" width="600" height="400" loading="lazy"><figcaption>Navegación inferior por pestañas (Bottom Tab Navigator) con el ícono "Home".</figcaption></figure><p>Lo anterior resultará en la pantalla anterior. Y similarmente, repitamos el mismo proceso para todas las pestañas de la navegación.</p><figure class="kg-card kg-code-card"><pre><code>&lt;Tab.Navigator&gt;
        &lt;Tab.Screen name="All" component={All}
          options={{
            tabBarIcon: (props) =&gt; (
              &lt;Icon type='feather' name='home' color={props.color} /&gt;
            ),
          }} /&gt;

        &lt;Tab.Screen name="Business" component={Business}
          options={{
            tabBarIcon: (props) =&gt; (
              &lt;Icon type='feather' name='dollar-sign' color={props.color} /&gt;
            ),
          }} /&gt;

        &lt;Tab.Screen name="Health" component={HealthScreen}
          options={{
            tabBarIcon: (props) =&gt; (
              &lt;Icon type='feather' name='heart' color={props.color} /&gt;
            ),
          }} /&gt;

        &lt;Tab.Screen name="Sports" component={SportsScreen}
          options={{
            tabBarIcon: (props) =&gt; (
              &lt;Icon type='ionicon' name="tennisball-outline" color={props.color} /&gt;
            ),
          }} /&gt;

        &lt;Tab.Screen name="Tech" component={TechScreen}
          options={{
            tabBarIcon: (props) =&gt; (
              &lt;Icon type='ionicon' name="hardware-chip-outline" color={props.color} /&gt;
            ),
          }} /&gt;
      &lt;/Tab.Navigator&gt;</code></pre><figcaption>Todas las pestañas (Bottom Tabs) con Íconos</figcaption></figure><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-21-194525.png" class="kg-image" alt="Screenshot-2021-08-21-194525" width="600" height="400" loading="lazy"></figure><p>Ahora cada una de las diferentes pestañas o pantallas esta lista y tienen su propio ícono distintivo.</p><h2 id="c-mo-llamar-al-api-de-noticias-news-api-">Cómo llamar al API de noticias (News API)</h2><p>Enseguida vamos a llamar al News API desde <a href="https://newsapi.org/">https://newsapi.org/</a></p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-21-194845.png" class="kg-image" alt="Screenshot-2021-08-21-194845" width="600" height="400" loading="lazy"></figure><p>Dirígete a este sitio web y date de alta. Ahí tendrás acceso a una clave API (API key).</p><p>Necesitaremos un archivo de configuración (config.js) para guardar todas las constantes con noticias (News), vamos a crearlo.</p><figure class="kg-card kg-code-card"><pre><code>export const API_KEY = ``;
export const endpoint = `https://newsapi.org/v2/top-headlines`;
export const country = 'in'</code></pre><figcaption>Nuestro archivo config.js</figcaption></figure><p>Necesitamos el API_KEY, el endpoint (url) y la clave de país.</p><p>Ahora necesitamos crear un servicio para realizar nuestra <strong>Solicitud GET </strong>al endpoint del API.</p><p>Crea un archivo con el nombre de <em>services.js.</em></p><p>Aquí importaremos el API_KEY, el endpoint (url) y la clave de país al inicio.</p><figure class="kg-card kg-code-card"><pre><code>import { API_KEY, endpoint, country } from '../config/config';</code></pre><figcaption>Services.js</figcaption></figure><p>Luego escribiremos el cuerpo de nuestro archivo services.js</p><figure class="kg-card kg-code-card"><pre><code>export async function services(category = 'general') {
    let articles = await fetch(`${endpoint}?country=${country}&amp;category=${category}`, {
        headers: {
            'X-API-KEY': API_KEY
        }
    });

    let result = await articles.json();
    articles = null;

    return result.articles;
}</code></pre><figcaption>Nuestro servicio GET API&nbsp;</figcaption></figure><p>Así que estamos solicitando los datos de las noticias usando nuestro "endpoint" url y concatenando el código de país además de la categoría. En la función pasamos la categoría "general" ya que es la categoría por defecto. También pasamos el API_key en la propiedad "headers".</p><p>Luego convertimos la respuesta, es decir los datos entrantes, al formato JSON y los almacenamos en la variable "result".</p><p>Y finalmente, los retornamos usando la palabra clave <code>return</code>.</p><p>Aquí está el contenido completo de este archivo para tu referencia:</p><pre><code>import { API_KEY, endpoint, country } from '../config/config';

export async function services(category = 'general') {
    let articles = await fetch(`${endpoint}?country=${country}&amp;category=${category}`, {
        headers: {
            'X-API-KEY': API_KEY
        }
    });

    let result = await articles.json();
    articles = null;

    return result.articles;
}</code></pre><p>Ahora necesitamos importar este servicio en nuestro archivo All.js.</p><figure class="kg-card kg-code-card"><pre><code>import { services } from '../services/services';</code></pre><figcaption>Importar services en All.js</figcaption></figure><p>Necesitaremos usar los "hooks" &nbsp;<code>useState</code> y <code>useEffect</code> , useEffect llamará a este servicio desde el archivo All.js y useState creará el estado que almacenará la respuesta que viene desde la API.</p><figure class="kg-card kg-code-card"><pre><code>import React, { useEffect, useState } from 'react'
import { View } from 'react-native';
import { services } from '../services/services';
export default function All() {
    const [newsData, setNewsData] = useState([])
    useEffect(() =&gt; {
        services('general')
            .then(data =&gt; {
                setNewsData(data)
            })
            .catch(error =&gt; {
                alert(error)
            })
    }, [])
    return (
        &lt;View&gt;

        &lt;/View&gt;
    )
}
</code></pre><figcaption>Usando los hooks useState y useEffect&nbsp;</figcaption></figure><p>En este archivo llamaremos a los servicios que se encuentran en nuestro useEffect "hook". Después almacenaremos la respuesta en el estado (state) de newsData que es un arreglo (array). También pasaremos un parámetro para la categoría que en este caso será "general".</p><p>En esta pantalla traeremos todas las noticias por lo que usaremos la categoría "general". La categoría cambiará para cada pantalla. Será health (salud) para la pantalla Health, sports (deportes) para la pantalla Sports y así sucesivamente.</p><p>Ahora necesitamos mostrar estos datos en nuestra interfaz. Y para ello, necesitamos incluso otro paquete llamado Native Base. Así que vayamos a instalarla.</p><p>Escribe y ejecuta los siguientes comandos para instalar "Native Base":</p><figure class="kg-card kg-code-card"><pre><code>yarn add native-base styled-components styled-system
expo install react-native-svg react-native-safe-area-context</code></pre><figcaption>Instalando Native Base</figcaption></figure><p>En el archivo All.js importaremos unas cuantas cosas de Native Base:</p><figure class="kg-card kg-code-card"><pre><code>import React, { useEffect, useState } from 'react'
import { View, Text } from 'react-native';
import { NativeBaseProvider, FlatList, ScrollView, Divider, Image, Spinner } from 'native-base';
import { services } from '../services/services';</code></pre><figcaption>Importando desde Native Base</figcaption></figure><p>Luego devolveremos el componente <code>NativeBaseProvider</code>.</p><figure class="kg-card kg-code-card"><pre><code>return (
        &lt;NativeBaseProvider&gt;
            
        &lt;/NativeBaseProvider&gt;
    )</code></pre><figcaption>Agregamos NativeBaseProvider en el return</figcaption></figure><p>Ahora agreguemos el Scroll View. Este habilitará a los usuarios para deslizar (scroll) la página hacia abajo en caso de que las noticias ocupen mayor espacio que el disponible para la altura de la pantalla.</p><figure class="kg-card kg-code-card"><pre><code>&lt;NativeBaseProvider&gt;
            &lt;ScrollView height={850}&gt;

            &lt;/ScrollView&gt;
        &lt;/NativeBaseProvider&gt;</code></pre><figcaption>Agregando el ScrollView</figcaption></figure><p>Ahora agreguemos al componente <code>FlatList</code> para mostrar las noticias.</p><figure class="kg-card kg-code-card"><pre><code>&lt;NativeBaseProvider&gt;
            &lt;ScrollView height={850}&gt;
                &lt;FlatList
                    data={newsData}
                    renderItem={({ item }) =&gt; (
                       &lt;View&gt;

                       &lt;/View&gt; 
                    )}
                    keyExtractor={(item) =&gt; item.id}
                /&gt;
            &lt;/ScrollView&gt;
        &lt;/NativeBaseProvider&gt;</code></pre><figcaption>Usando el componente FlatList</figcaption></figure><p>El componente FlatList recibe una propiedad o prop "data" a la cual pasaremos nuestro estado (state) creado anteriormente <code>newsData</code> y devolverá un <code>item</code> de los <code>renderItems</code>.</p><p>Esto es similar a un <code>map</code> en JavaScript, que recorre un arreglo y retorna un elemento. También cuenta con un <code>keyExtractor</code> que usaremos para hacer cada elemento único.</p><p>Ahora, mostremos nuestros datos usando el componente View.</p><p>Crea otro componente View dentro del ya existente componente View, así:</p><pre><code>&lt;NativeBaseProvider&gt;
            &lt;ScrollView height={850}&gt;
                &lt;FlatList
                    data={newsData}
                    renderItem={({ item }) =&gt; (
                       &lt;View&gt;
                           &lt;View&gt;
                               
                           &lt;/View&gt;
                       &lt;/View&gt; 
                    )}
                    keyExtractor={(item) =&gt; item.id}
                /&gt;
            &lt;/ScrollView&gt;
        &lt;/NativeBaseProvider&gt;</code></pre><p>Ahora vamos a agregar algo de texto dentro del componente View hijo.</p><pre><code>&lt;NativeBaseProvider&gt;
            &lt;ScrollView height={850}&gt;
                &lt;FlatList
                    data={newsData}
                    renderItem={({ item }) =&gt; (
                        &lt;View&gt;
                            &lt;View&gt;
                                &lt;Text&gt;
                                    {item.title}
                                &lt;/Text&gt;
                                &lt;Text&gt;
                                    {item.publishedAt}
                                &lt;/Text&gt;
                                &lt;Text&gt;
                                    {item.description}
                                &lt;/Text&gt;
                            &lt;/View&gt;
                        &lt;/View&gt;
                    )}
                    keyExtractor={(item) =&gt; item.id}
                /&gt;
            &lt;/ScrollView&gt;
        &lt;/NativeBaseProvider&gt;</code></pre><p>Este contiene nuestro titular de noticias, la descripción y la fecha de publicación.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-21-203253.png" class="kg-image" alt="Screenshot-2021-08-21-203253" width="600" height="400" loading="lazy"></figure><p></p><h2 id="c-mo-estilizar-nuestra-app-de-noticias">Cómo estilizar nuestra app de noticias </h2><p>Ya vimos la apariencia que tiene nuestra app hasta ahora, con el título de las noticias, la descripción y la fecha. Para hacerlo verse un poco mejor necesitamos darle algo de estilo.</p><p>Importa <code>StyleSheet</code> desde Reac Native al principio del archivo para poder usarlo para estilizar nuestra app.</p><figure class="kg-card kg-code-card"><pre><code>import { View, Text, StyleSheet } from 'react-native';</code></pre><figcaption>Importando StyleSheet desde react-native</figcaption></figure><p>Luego, agrega los estilos de la siguiente manera.</p><pre><code>&lt;View&gt;
                            &lt;View style={styles.newsContainer}&gt;
                                &lt;Text style={styles.title}&gt;
                                    {item.title}
                                &lt;/Text&gt;
                                &lt;Text style={styles.date}&gt;
                                    {item.publishedAt}
                                &lt;/Text&gt;
                                &lt;Text style={styles.newsDescription}&gt;
                                    {item.description}
                                &lt;/Text&gt;
                            &lt;/View&gt;
                        &lt;/View&gt;</code></pre><p> Y al final del archivo necesitamos crear esos estilos.</p><figure class="kg-card kg-code-card"><pre><code>const styles = StyleSheet.create({
    newsContainer: {
        padding: 10
    },
    title: {
        fontSize: 18,
        marginTop: 10,
        fontWeight: "600"
    },
    newsDescription: {
        fontSize: 16,
        marginTop: 10
    },
    date: {
        fontSize: 14
    },
});</code></pre><figcaption>Nuestra hoja de estilos StyleSheet en All.js</figcaption></figure><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-21-203824.png" class="kg-image" alt="Screenshot-2021-08-21-203824" width="600" height="400" loading="lazy"></figure><p>Y así es cómo queda la aplicación luego de haber agregado algunas reglas de estilo css. También puedes deslizar la página hacia abajo.</p><p>Ahora necesitamos cambiar el formato de la fecha a uno que mejore su legibilidad, es decir que haga más fácil su lectura, ya que es díficil para una persona entender una fecha cómo <strong>'2021-08-21T11:00:40Z'.</strong></p><p>Para este fin usaremos el útil paquete moment.js, así que instalemos moment usando el siguiente comando:</p><figure class="kg-card kg-code-card"><pre><code>npm install moment --save</code></pre><figcaption>Instalemos Moment.js para darle formato a las fechas.</figcaption></figure><p>Luego lo importamos en nuestro archivo All.js para poder utilizarlo.</p><figure class="kg-card kg-code-card"><pre><code>&lt;Text style={styles.date}&gt;
  {moment(item.publishedAt).format('LLL')}
&lt;/Text&gt;</code></pre><figcaption>Aplicando un formato para fecha y hora usando moment.js</figcaption></figure><p>Podemos usar los siguientes formatos:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-21-204311.png" class="kg-image" alt="Screenshot-2021-08-21-204311" width="600" height="400" loading="lazy"><figcaption>Distintos formatos de Moment.js para fechas y horas.</figcaption></figure><p>En la documentación de moment se nos brindan muchos formatos distintos de los cuáles elegir. Para este caso he elegido el formato 'LLL'.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-21-204439.png" class="kg-image" alt="Screenshot-2021-08-21-204439" width="600" height="400" loading="lazy"></figure><p>Y ahora nuestras fechas son mucho más fáciles de leer y entender.</p><p>También necesitamos un separador para dividir unos artículos de noticias de otros en la lista y así mejorar tanto su apariencia cómo su legibilidad.</p><figure class="kg-card kg-code-card"><pre><code>&lt;View&gt;
                            &lt;View style={styles.newsContainer}&gt;
                                &lt;Text style={styles.title}&gt;
                                    {item.title}
                                &lt;/Text&gt;
                                &lt;Text style={styles.date}&gt;
                                    {moment(item.publishedAt).format('LLL')}
                                &lt;/Text&gt;
                                &lt;Text style={styles.newsDescription}&gt;
                                    {item.description}
                                &lt;/Text&gt;
                            &lt;/View&gt;
                            &lt;Divider my={2} bg="#e0e0e0" /&gt;
                        &lt;/View&gt;</code></pre><figcaption>Agregando un separador</figcaption></figure><p>Luego de haber dividido cada View hijo nuestra aplicación se verá así:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-21-204707.png" class="kg-image" alt="Screenshot-2021-08-21-204707" width="600" height="400" loading="lazy"></figure><p>Ahora los titulares y noticias estarán separados, lo que hace que se vean muy bien.</p><p>Esta API de noticias nos da acceso a una imágen también, así que vamos a agregarla.</p><pre><code>&lt;View&gt;
                            &lt;View style={styles.newsContainer}&gt;
                                &lt;Image
                                    width={550}
                                    height={250}
                                    resizeMode={"cover"}
                                    source={{
                                        uri: item.urlToImage,
                                    }}
                                    alt="Alternate Text"
                                /&gt;
                                &lt;Text style={styles.title}&gt;
                                    {item.title}
                                &lt;/Text&gt;
                                &lt;Text style={styles.date}&gt;
                                    {moment(item.publishedAt).format('LLL')}
                                &lt;/Text&gt;
                                &lt;Text style={styles.newsDescription}&gt;
                                    {item.description}
                                &lt;/Text&gt;
                            &lt;/View&gt;
                            &lt;Divider my={2} bg="#e0e0e0" /&gt;
                        &lt;/View&gt;</code></pre><p>Ya hemos agregado la imágen usando la "key" (clave) llamada <code>urlToImage</code> para esta finalidad.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-21-204945.png" class="kg-image" alt="Screenshot-2021-08-21-204945" width="600" height="400" loading="lazy"></figure><p>Ahora ya podemos ver las imágenes que corresponden a cada noticia.</p><h2 id="c-mo-agregar-un-spinner-para-mostrar-cu-ndo-las-noticias-se-est-n-cargando">Cómo agregar un Spinner para mostrar cuándo las noticias se estén cargando</h2><p>Agreguemos un spinner que mostrará cuando las noticias se estén cargando.</p><p>Primero crearemos una condición. Si el tamaño del estado (state) de <code>newsData</code> es mayor a uno, mostraremos nuestro componente <code>FlatList</code> , que contiene los datos de nuestras noticias. Sino, entonces mostraremos el spinner cargando.</p><p>En otras palabras si el tamaño del estado (state) <code>newsData</code> es menor a uno, quiere decir que el arreglo está vació y que la llamada al API aún se esté ejecutando. Una vez que la llamada al API concluya, almacenará los datos en el estado <code>newsData</code> y el tamaño de este arreglo aumentará de cero a uno o mayor.</p><figure class="kg-card kg-code-card"><pre><code>{newsData.length &gt; 1 ? (
                    &lt;FlatList
                        data={newsData}
                        renderItem={({ item }) =&gt; (
                            &lt;View&gt;
                                &lt;View style={styles.newsContainer}&gt;
                                    &lt;Image
                                        width={550}
                                        height={250}
                                        resizeMode={"cover"}
                                        source={{
                                            uri: item.urlToImage,
                                        }}
                                        alt="Alternate Text"
                                    /&gt;
                                    &lt;Text style={styles.title}&gt;
                                        {item.title}
                                    &lt;/Text&gt;
                                    &lt;Text style={styles.date}&gt;
                                        {moment(item.publishedAt).format('LLL')}
                                    &lt;/Text&gt;
                                    &lt;Text style={styles.newsDescription}&gt;
                                        {item.description}
                                    &lt;/Text&gt;
                                &lt;/View&gt;
                                &lt;Divider my={2} bg="#e0e0e0" /&gt;
                            &lt;/View&gt;
                        )}
                        keyExtractor={(item) =&gt; item.id}
                    /&gt;
                ) : (
                    &lt;View style={styles.spinner}&gt;
                        &lt;Spinner color="danger.400" /&gt;
                    &lt;/View&gt;
                )}</code></pre><figcaption>Agregando un Spinner</figcaption></figure><p>Y en nuestros estilos agregaremos el siguiente código para el spinner.</p><figure class="kg-card kg-code-card"><pre><code>spinner: {
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        height: 400
}</code></pre><figcaption>Estilos para el Spinner</figcaption></figure><p>Aquí abajo está el código de referencia:</p><pre><code>import React, { useEffect, useState } from 'react'
import { View, Text, StyleSheet } from 'react-native';
import { NativeBaseProvider, FlatList, ScrollView, Divider, Image, Spinner } from 'native-base';
import { services } from '../services/services';
import moment from 'moment'
export default function All() {
    const [newsData, setNewsData] = useState([])
    useEffect(() =&gt; {
        services('general')
            .then(data =&gt; {
                setNewsData(data)
            })
            .catch(error =&gt; {
                alert(error)
            })
    }, [])
    return (
        &lt;NativeBaseProvider&gt;
            &lt;ScrollView height={850}&gt;
                {newsData.length &gt; 1 ? (
                    &lt;FlatList
                        data={newsData}
                        renderItem={({ item }) =&gt; (
                            &lt;View&gt;
                                &lt;View style={styles.newsContainer}&gt;
                                    &lt;Image
                                        width={550}
                                        height={250}
                                        resizeMode={"cover"}
                                        source={{
                                            uri: item.urlToImage,
                                        }}
                                        alt="Alternate Text"
                                    /&gt;
                                    &lt;Text style={styles.title}&gt;
                                        {item.title}
                                    &lt;/Text&gt;
                                    &lt;Text style={styles.date}&gt;
                                        {moment(item.publishedAt).format('LLL')}
                                    &lt;/Text&gt;
                                    &lt;Text style={styles.newsDescription}&gt;
                                        {item.description}
                                    &lt;/Text&gt;
                                &lt;/View&gt;
                                &lt;Divider my={2} bg="#e0e0e0" /&gt;
                            &lt;/View&gt;
                        )}
                        keyExtractor={(item) =&gt; item.id}
                    /&gt;
                ) : (
                    &lt;View style={styles.spinner}&gt;
                        &lt;Spinner color="danger.400" /&gt;
                    &lt;/View&gt;
                )}
            &lt;/ScrollView&gt;
        &lt;/NativeBaseProvider&gt;
    )
}

const styles = StyleSheet.create({
    newsContainer: {
        padding: 10
    },
    title: {
        fontSize: 18,
        marginTop: 10,
        fontWeight: "600"
    },
    newsDescription: {
        fontSize: 16,
        marginTop: 10
    },
    date: {
        fontSize: 14
    },
    spinner: {
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        height: 400
    }
});</code></pre><p>Nuestra vista All.js está ahora completa.</p><p>Y ahora podemos usar el mismo código en todas nuestras otras vistas también. Sólo necesitamos cambiar el parámetro que estamos pasando en los servicios del <code>useEffect</code> Hook.</p><p>Así que para la vista "Business" (negocios) usaremos la palabra "business", para Health usaremos "health", etc.</p><figure class="kg-card kg-code-card"><pre><code>import React, { useEffect, useState } from 'react'
import { View, Text, StyleSheet } from 'react-native';
import { NativeBaseProvider, FlatList, ScrollView, Divider, Image, Spinner } from 'native-base';
import { services } from '../services/services';
import moment from 'moment'
export default function Business() {
    const [newsData, setNewsData] = useState([])
    useEffect(() =&gt; {
        services('business')
            .then(data =&gt; {
                setNewsData(data)
            })
            .catch(error =&gt; {
                alert(error)
            })
    }, [])
    return (
        &lt;NativeBaseProvider&gt;
            &lt;ScrollView height={850}&gt;
                {newsData.length &gt; 1 ? (
                    &lt;FlatList
                        data={newsData}
                        renderItem={({ item }) =&gt; (
                            &lt;View&gt;
                                &lt;View style={styles.newsContainer}&gt;
                                    &lt;Image
                                        width={550}
                                        height={250}
                                        resizeMode={"cover"}
                                        source={{
                                            uri: item.urlToImage,
                                        }}
                                        alt="Alternate Text"
                                    /&gt;
                                    &lt;Text style={styles.title}&gt;
                                        {item.title}
                                    &lt;/Text&gt;
                                    &lt;Text style={styles.date}&gt;
                                        {moment(item.publishedAt).format('LLL')}
                                    &lt;/Text&gt;
                                    &lt;Text style={styles.newsDescription}&gt;
                                        {item.description}
                                    &lt;/Text&gt;
                                &lt;/View&gt;
                                &lt;Divider my={2} bg="#e0e0e0" /&gt;
                            &lt;/View&gt;
                        )}
                        keyExtractor={(item) =&gt; item.id}
                    /&gt;
                ) : (
                    &lt;View style={styles.spinner}&gt;
                        &lt;Spinner color="danger.400" /&gt;
                    &lt;/View&gt;
                )}
            &lt;/ScrollView&gt;
        &lt;/NativeBaseProvider&gt;
    )
}

const styles = StyleSheet.create({
    newsContainer: {
        padding: 10
    },
    title: {
        fontSize: 18,
        marginTop: 10,
        fontWeight: "600"
    },
    newsDescription: {
        fontSize: 16,
        marginTop: 10
    },
    date: {
        fontSize: 14
    },
    spinner: {
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        height: 400
    }
});</code></pre><figcaption>La vista o pantalla para la categoría Business</figcaption></figure><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2021/08/Screenshot-2021-08-21-210200.png" class="kg-image" alt="Screenshot-2021-08-21-210200" width="600" height="400" loading="lazy"></figure><p>Recorrete hacia abajo en la vista Business y verás noticias relacionadas a esta categoría.</p><p>Y podrás hacer lo mismo para todas las pantallas:</p><figure class="kg-card kg-code-card"><pre><code>useEffect(() =&gt; {
        services('business')
            .then(data =&gt; {
                setNewsData(data)
            })
            .catch(error =&gt; {
                alert(error)
            })
}, [])</code></pre><figcaption>Para Business</figcaption></figure><figure class="kg-card kg-code-card"><pre><code>useEffect(() =&gt; {
        services('health')
            .then(data =&gt; {
                setNewsData(data)
            })
            .catch(error =&gt; {
                alert(error)
            })
    }, [])</code></pre><figcaption>Para Health</figcaption></figure><figure class="kg-card kg-code-card"><pre><code>useEffect(() =&gt; {
        services('sports')
            .then(data =&gt; {
                setNewsData(data)
            })
            .catch(error =&gt; {
                alert(error)
            })
    }, [])</code></pre><figcaption>Para Sports</figcaption></figure><figure class="kg-card kg-code-card"><pre><code>useEffect(() =&gt; {
        services('technology')
            .then(data =&gt; {
                setNewsData(data)
            })
            .catch(error =&gt; {
                alert(error)
            })
    }, [])</code></pre><figcaption>Para Tech</figcaption></figure><h2 id="conclusi-n">Conclusión</h2><p>Felicidades! </p><p>Ahora nuetra aplicación de noticias está completa.</p><p>Así que adelante! Crea y experiumenta con esta aplicación. Hay muchas cosas que puedes hacer.</p><p>Se bienvenido a descargar el código fuente en: <a href="https://github.com/nishant-666/React-Native-News">https://github.com/nishant-666/React-Native-News</a></p><blockquote>Feliz Aprendizaje.</blockquote> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ React.js: implementar la funcion de arrastrar y soltar sin usar librerías de terceros ]]>
                </title>
                <description>
                    <![CDATA[ Entremos en detalle acerca de la implementación de la funcionalidad de arrastrar y soltar en React desde cero.  Veamos primero el resultado de lo que vamos a construir. Te lo muestro por medio de un .gif; espero que este se visualice correctamente, para ello he utilizado Camtasia con una ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/react-js-implementar-la-funcion-de-arrastrar-y-soltar-sin-usar-librerias-de-terceros/</link>
                <guid isPermaLink="false">642779c6cbd6cf076f06a7ba</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Palma ]]>
                </dc:creator>
                <pubDate>Fri, 14 Apr 2023 18:37:01 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/04/1-hPLhe5cqPbyE8Hi4CGQMYg-1.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/reactjs-implement-drag-and-drop-feature-without-using-external-libraries-ad8994429f1a/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">React.js: implement the drag and drop feature without using external libraries</a>
      </p><h4 id="entremos-en-detalle-acerca-de-la-implementaci-n-de-la-funcionalidad-de-arrastrar-y-soltar-en-react-desde-cero-">Entremos en detalle acerca de la implementación de la funcionalidad de arrastrar y soltar en React desde cero. </h4><p>Veamos primero el resultado de lo que vamos a construir. Te lo muestro por medio de un .gif; espero que este se visualice correctamente, para ello he utilizado Camtasia con una licencia de uso personal.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/1*Y11YSJEJ9A4JFGllOQSroQ.gif" class="kg-image" alt="1*Y11YSJEJ9A4JFGllOQSroQ" width="800" height="450" loading="lazy"><figcaption>Ignora por favor la interfaz y el estilo actual!</figcaption></figure><p>Los puntos clave para aprender son:</p><ol><li>Haz que el elemento arrastrable añadiendo el atributo "draggable" </li><li>Haz que un área sea desplegable implementando el evento “dragover”</li><li>Captura los datos arrastrados al implementar &nbsp;el evento “dragstart”.</li><li>Captura la caída implementando el evento "drop".</li><li>Implementar el evento "drag" que se dispara al arrastrar el elemento.</li><li>Almacenar los datos intermedios en el objeto dataTransfer (transferenciaDeDatos)</li></ol><p>Para los que aprenden visualmente, pueden ver el vídeo a continuación.</p><h3 id="paso-1-crear-la-aplicaci-n-ra-z-para-el-demo">Paso 1 – crear la aplicación raíz para el demo</h3><p>Todo el código para arrastrar y soltar irá en el componente AppDragDropDemo.js.</p><figure class="kg-card kg-code-card"><pre><code>import React from 'react';
import ReactDOM from 'react-dom';import '.index.css';
import AppDragDropDemo from './AppDragDropDemo';</code></pre><figcaption>Importando las dependencias en el archivo raíz, para renderizar nuestro componente.</figcaption></figure><figure class="kg-card kg-code-card"><pre><code>ReactDOM.render(
	&lt;AppDragDropDemo /&gt;,     
    document.getElementById("root")
);</code></pre><figcaption>Renderizando el componente usando ReactDOM.render()</figcaption></figure><p>El punto de entrada para la aplicación AppDragDropDemo se verá como en el código de abajo.</p><pre><code>import React, { Component } from 'react';</code></pre><pre><code>export default class AppDragDropDemo extends Component {  
    render () {    
    	return (
            &lt;div className="container-drag"&gt;        
            	DRAG &amp; DROP DEMO      
            &lt;/div&gt;);  
     }
 }</code></pre><p>Si corres la aplicación, se te mostrará esta increíble pantalla (broma intencional):</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*16qtjJ6Bh53hsY2z4oi2gw.png" class="kg-image" alt="1*16qtjJ6Bh53hsY2z4oi2gw" width="399" height="106" loading="lazy"></figure><h3 id="paso-2-crear-el-objeto-estado-state-para-almacenar-algunas-tareas-">Paso 2 – crear el objeto estado (state) para almacenar algunas tareas.</h3><p>Vamos a crear algunas tareas para simular una simple aplicación. Lo que queremos hacer es "arrastrar y soltar" estas tareas en diferentes categorías como <code>wip</code>, <code>complete</code>, y demás.</p><figure class="kg-card kg-code-card"><pre><code>export default class AppDragDropDemo extends Component {      
	state = {            
    	tasks: [
        	{
            	name:"Learn Angular",             
        		category:"wip",              
        		bgcolor: "yellow"
     		},
     		{
            	name:"React",              
     			category:"wip",              
                bgcolor:"pink"
             },                        
             {
             	name:"Vue",              
                category:"complete",              
                bgcolor:"skyblue"
              }                
         ]
    }</code></pre><figcaption>Código del componente AppDragDropDemo</figcaption></figure><pre><code>  render () {    
  	return (      
    	&lt;div className="container-drag"&gt;        
        	DRAG &amp; DROP DEMO      
        &lt;/div&gt;);  
    }
 }</code></pre><h3 id="paso-3-organizar-nuestros-datos-en-categor-as-">Paso 3 — Organizar nuestros datos en categorías.</h3><p>Vamos a implementar el siguiente código en el método render, para agrupar las tareas en sus respectivas categorías <code>wip</code> y <code>complete</code>. Siéntete libre de añadir más categorías y jugar con el código.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*u7edSd4vxCBW_JMnA1qbYA.png" class="kg-image" alt="1*u7edSd4vxCBW_JMnA1qbYA" width="666" height="380" loading="lazy"></figure><p>También puedes copiar y pegar este código desde el fragmento de abajo.</p><pre><code>render() {          
	var tasks = { 
    	wip: [], 
        complete: []
    }
    
    this.state.tasks.forEach ((t) =&gt; {     
    	tasks[t.category].push(
        	&lt;div    key={t.name}                           
            		onDragStart={(e)=&gt;this.onDragStart(e, t.name)}                          		 draggable                          
                    className="draggable"                          
                    style={{backgroundColor: t.bgcolor}}&gt;
                     
                     {t.name}                    
             &lt;/div&gt;);          
     });
}</code></pre><p>En el código de arriba, estamos recorriendo las tareas, creando un div para cada una y guardándolo en las respectivas categorías.</p><p>Así que &nbsp;<code>wip[]</code> contiene todas las tareas de la categoría &nbsp;wip y <code>complete[]</code> contiene todas las tareas completadas.</p><h3 id="paso-4-haz-que-el-elemento-de-tarea-se-pueda-arrastrar-">Paso 4 — Haz que el elemento de "tarea" se pueda arrastrar.</h3><p>Agrega el atributo "draggable" al &lt;div&gt; o a cualquier elemento que desees hacer arrastrable. Usa el bloque de código anterior o el de abajo como referencia para el formato del texto.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/04/Hacer-un-elemento-arrastrable-2.jpg" class="kg-image" alt="Hacer-un-elemento-arrastrable-2" srcset="https://www.freecodecamp.org/espanol/news/content/images/2023/04/Hacer-un-elemento-arrastrable-2.jpg 600w" width="600" height="380" loading="lazy"></figure><h3 id="paso-5-crear-un-contenedor-desplegable">Paso 5 — crear un contenedor desplegable</h3><p>Para crear un contenedor desplegable, o "droppable" implementa el evento dragover. Ahora, como queremos deshabilitar el comportamiento por defecto del evento dragover, debemos simplemente llamar <code>event.preventDefault()</code> desde el objeto <code>event</code> que recibimos del evento dragover.</p><p>También renderizaremos <code>{tasks.wip}</code> y <code>{tasks.complete}</code> en sus elementos div correspondientes.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/04/Hacer-un-elemento-arrastrable-2-1.jpg" class="kg-image" alt="Hacer-un-elemento-arrastrable-2-1" srcset="https://www.freecodecamp.org/espanol/news/content/images/2023/04/Hacer-un-elemento-arrastrable-2-1.jpg 600w" width="600" height="380" loading="lazy"></figure><pre><code>return (
	&lt;div className="container-drag"&gt;     
    	&lt;h2 className="header"&gt;DRAG &amp; DROP DEMO&lt;/h2&gt;                       
        &lt;div className="wip"        
        	 onDragOver={(e)=&gt;this.onDragOver(e)} 
             onDrop={(e)=&gt;{this.onDrop(e, "wip")}}&gt; 
             	&lt;span className="task-header"&gt;WIP&lt;/span&gt;    
                	{tasks.wip}                     
         &lt;/div&gt;                     
         &lt;div className="droppable"      
         	  onDragOver={(e)=&gt;this.onDragOver(e)}  
              onDrop={(e)=&gt;this.onDrop(e, "complete")}&gt;
              	&lt;span className="task-header"&gt;COMPLETED&lt;/span&gt;  
                	{tasks.complete}                     
         &lt;/div&gt;               
    &lt;/div&gt;
);</code></pre><pre><code>Implementemos ahora para el evento onDragOver() su correspondiente función o event handler.</code></pre><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*hNDl0tztfkDNddbIN4cVew.png" class="kg-image" alt="1*hNDl0tztfkDNddbIN4cVew" width="464" height="75" loading="lazy"></figure><p>El resultado hasta ahora se verá como en la captura de pantalla que se muestra abajo.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*fHaKQZ_1Iw0J1bFlIufbTw.png" class="kg-image" alt="1*fHaKQZ_1Iw0J1bFlIufbTw" width="800" height="216" loading="lazy"></figure><h3 id="paso-6-captura-el-estado-del-elemento-arrastrado-">Paso 6 — captura el estado del elemento arrastrado.</h3><p>Vamos a modificar el código dónde creamos la categoría para cada tarea. Agregaremos una función para responder al evento (event handler) <code>ondragstart</code> y pasa el identificador, nombre (id/name) o cualquier información que necesites guardar mientras sucede el arrastrado/soltado.</p><p>Estoy usando <code>name</code> (nombre) cómo valor único para identificar una tarea. Siéntate libre de usar ID o cualquier clave única que gustes.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/04/Hacer-un-elemento-arrastrable-3-2.jpg" class="kg-image" alt="Hacer-un-elemento-arrastrable-3-2" srcset="https://www.freecodecamp.org/espanol/news/content/images/2023/04/Hacer-un-elemento-arrastrable-3-2.jpg 600w" width="600" height="253" loading="lazy"></figure><p>Ahora implementemos la función para responder al evento &nbsp;<code>onDragStart</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/04/Hacer-un-elemento-arrastrable-4.jpg" class="kg-image" alt="Hacer-un-elemento-arrastrable-4" srcset="https://www.freecodecamp.org/espanol/news/content/images/2023/04/Hacer-un-elemento-arrastrable-4.jpg 600w" width="600" height="253" loading="lazy"></figure><p>En el manejador onDragStart, tomamos el parámetro y lo almacenamos dentro del objeto dataTransfer. (*Nota: no te confundas con el nombre del parámetro).</p><p>*Nota para IE (Internet Explorer): este código podría no funcionar en IE, ya que la mejor práctica es darle formato como te muestro a continuación:</p><pre><code>En lugar de:</code></pre><pre><code>ev.dataTransfer.setData("id", id)</code></pre><pre><code>USAR:</code></pre><pre><code>ev.dataTransfer.setData(“text/plain”,id)</code></pre><p>En manejador anterior asegurará de que el elemento que se arrastra sea almacenado en el objeto "event" y está disponible para su uso cuando sea requerido. Este podría requerirse mientras soltamos en el contendor que será el objetivo.</p><p>Ahora si corres la aplicación y arrastras los elementos, podrás ver los siguientes logs en consola.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*T9eejIeJ6gZJGWFoLxXxgg.png" class="kg-image" alt="1*T9eejIeJ6gZJGWFoLxXxgg" width="800" height="343" loading="lazy"></figure><h3 id="paso-7-manejar-el-evento-drop-soltar-">Paso 7 — Manejar el evento drop (soltar).</h3><p>Vamos al método render y añadamos el evento <code>onDrop</code> al div con el atributo className con valor <code>droppable</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/04/Hacer-un-elemento-arrastrable-5.jpg" class="kg-image" alt="Hacer-un-elemento-arrastrable-5" srcset="https://www.freecodecamp.org/espanol/news/content/images/2023/04/Hacer-un-elemento-arrastrable-5.jpg 600w" width="600" height="253" loading="lazy"></figure><p>En el código de arriba, agregamos la función para responder al evento <code>drop</code> y pasar la categoría requerida ( <code>complete</code> ) como argumento. Esto indica que estamos soltando el elemento desde el estado <code>wip</code> hacia el estado <code>complete</code> que representa una categoría. Siéntete bienvenido a cambiar los nombres cómo veas conveniente.</p><p>Ahora implementemos la función o handler para responder al evento <code>onDrop</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/04/Hacer-un-elemento-arrastrable-6.jpg" class="kg-image" alt="Hacer-un-elemento-arrastrable-6" srcset="https://www.freecodecamp.org/espanol/news/content/images/2023/04/Hacer-un-elemento-arrastrable-6.jpg 600w" width="600" height="253" loading="lazy"></figure><p>Acá puedes copiar para luego pegar el código. </p><pre><code>onDrop = (ev, cat) =&gt; {         
	let id = ev.dataTransfer.getData("id");  
    let tasks = this.state.tasks.filter((task) =&gt; {      
    	if (task.name == id) {               
            task.category = cat;                 }                     
            return task;          
     });           
     this.setState({                 
     	...this.state,                 
        tasks          
     });    
}</code></pre><p>En el handler para el evento <code>onDrop</code> , tomamos la tarea que se está arrastrando mediante el uso del método getData en el objeto dataTransfer del evento.</p><p>Luego creamos el arreglo con las nuevas tareas mediante el uso del método filter y cambiamos la categoría de la tarea que se está arrastrando.</p><p><code>setState()</code> desatará el renderizado y las tareas serán desplegadas en las áreas correctas.</p><p>*Note de <strong>IE: </strong>para lograr que esto funcione en IE usa el método getData de abajo.</p><p>En lugar de</p><p><strong>var id = ev.dataTransfer.getData(“id”)</strong></p><p>usar</p><p><strong>var id = ev.dataTransfer.getData(“text”)</strong></p><h3 id="paso-8-para-implementar-el-soltado-desde-complete-hasta-wip-agrega-el-handler-para-el-evento-ondrop">Paso 8 — para implementar el soltado desde "complete" hasta "wip" agrega el handler para el evento onDrop</h3><p>El handler o función de respuesta para el evento <code>onDrop()</code> permanece igual que antes.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2023/04/Hacer-un-elemento-arrastrable-7.jpg" class="kg-image" alt="Hacer-un-elemento-arrastrable-7" srcset="https://www.freecodecamp.org/espanol/news/content/images/2023/04/Hacer-un-elemento-arrastrable-7.jpg 600w" width="600" height="253" loading="lazy"></figure><p>Finalmente corre el código y maravíllate de tu creación :) además claro diviértete programando.</p><p>Puedes tomar el código fuente de <a href="https://github.com/rajeshpillai/youtube-react-components/blob/master/src/AppDragDropDemo.js" rel="noopener">aquí</a>.</p><p><strong>Nota:</strong> para que este código funcione en los navegadores principales, cambia el tipo de datos de setData a string. Por ejemplo, para cambiar los datos usa <code><strong>ev.dataTransfer.setData(“text/plain”,id)</strong></code>. Para leer datos usa <strong> </strong> <code><strong>var id = ev.dataTransfer.getData(“text”)</strong></code>.</p><p>Ya que mi objetivo era demostrar la funcionalidad esencial de la característica de "arrastrar y soltar" el código no ha sido optimizado para contemplar factores cómo el diseño y las convenciones de nombres.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo crear una aplicación React con un Backend de Node: La guía completa ]]>
                </title>
                <description>
                    <![CDATA[ Un frontend con React conectado a un backend usando Node es una combinación sólida para cualquier aplicación que quieras construir. Esta guía está diseñada para ayudarte a crear proyectos full-stack con React de forma tan fácil como sea posible. Veamos como configurar un proyecto completo usando React y Node desde ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-crear-una-aplicacion-react-con-un-backend-de-node-la-guia-completa/</link>
                <guid isPermaLink="false">62910b1b17d14108aa145fca</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Palma ]]>
                </dc:creator>
                <pubDate>Fri, 15 Jul 2022 21:01:09 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2022/07/how-to-build-a-react-app-with-a-node-backend-alt.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-create-a-react-app-with-a-node-backend-the-complete-guide/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Create a React App with a Node Backend: The Complete Guide</a>
      </p><p>Un frontend con React conectado a un backend usando Node es una combinación sólida para cualquier aplicación que quieras construir.</p><p>Esta guía está diseñada para ayudarte a crear proyectos full-stack con React de forma tan fácil como sea posible.</p><p>Veamos como configurar un proyecto completo usando React y Node desde cero y desplegarlo en la web.</p><h2 id="herramientas-que-necesitar-s">Herramientas que necesitarás</h2><ol><li>Asegúrate de tener Node y NPM instalados en tu computadora. Puedes descargar ambos en <a href="https://nodejs.org/">nodejs.org</a> (NPM viene incluido con la instalación de Node).</li><li>Utiliza el editor de código de tu preferencia. Yo estoy usando VSCode y personalmente recomiendo usarlo. Puedes descargar VSCode de <a href="https://code.visualstudio.com/">code.visualstudio.com</a>.</li><li>Asegúrate de tener Git instalado en tu computadora. Esto es necesario para desplegar nuestra aplicación con Heroku. Puedes descargarlo de <a href="https://git-scm.com/">git-scm.com</a></li><li>Una cuenta en <a href="https://heroku.com/">heroku.com</a>. Usaremos Heroku para publicar nuestra aplicación a la web completamente gratis.</li></ol><h2 id="paso-1-crea-tu-backend-node-express-">Paso 1: Crea tu backend Node (Express) </h2><p>Primero crea una carpeta en tu proyecto con el nombre <code>react-node-app</code> (por ejemplo).</p><p>Luego arrástralo al editor de código. </p><p>Para crear nuestro proyecto Node, ejecuta el siguiente comando en tu terminal o línea de comandos:</p><pre><code class="language-bash">npm init -y</code></pre><p>Esto creará el archivo package.json que permitirá dar seguimiento a todos los scripts de nuestra app y manejar cualquiera de las dependencias que necesite nuestra app.</p><p>El código de nuestro servidor vivirá en una carpeta con el nombre <code>server</code>. Vayamos a crearlo.</p><p>Ahí dentro pondremos un solo archivo, desde el cual correremos nuestro servidor: <code>index.js</code>.</p><p>Usaremos Express para crear un servidor web simple para que corra en el puerto 3001 por defecto, es decir, al no darle un valor distinto a la variable de entorno, <code>PORT</code> Heroku le dará este valor (3001) cuando despleguemos nuestra aplicación.</p><pre><code class="language-js">// server/index.js

const express = require("express");

const PORT = process.env.PORT || 3001;

const app = express();

app.listen(PORT, () =&gt; {
  console.log(`Server listening on ${PORT}`);
});</code></pre><p>Luego en nuestra terminal instalaremos Express como una dependencia para utilizar en nuestro proyecto:</p><pre><code class="language-bash">npm i express</code></pre><p>Luego de esto, crearemos un script en el archivo package.json que iniciará la ejecución de nuestro servidor web con el comando <code>npm start</code>:</p><pre><code class="language-json">// server/package.json

...
"scripts": {
  "start": "node index.js"
},
...</code></pre><p>Finalmente, podemos correr nuestra aplicación usando este script con el comando <code>npm start</code> en nuestra terminal y deberíamos verlo ejecutándose en el puerto 3001:</p><pre><code class="language-bash">npm start

&gt; node index.js

Server listening on 3001 (servidor escuchando en el puerto 3001)</code></pre><figure class="kg-card kg-image-card"><img src="https://reedbarger.nyc3.digitaloceanspaces.com/how-to-create-a-react-app-with-a-node-backend/clip-1.gif" class="kg-image" alt="Clip 1" width="600" height="400" loading="lazy"></figure><h2 id="paso-2-crear-el-api-endpoint">Paso 2: Crear el API Endpoint</h2><p>Queremos usar nuestro servidor Node/Express como una API (Interfaz de Programación de Aplicaciones), para que pueda darle datos a nuestra app React, así como también la capacidad de editar los datos o realizar alguna operación que solo el servidor puede hacer.</p><p>En nuestro caso, podemos simplemente enviar un mensaje a nuestro app React que diga "Hola desde el servidor!", en un objeto JSON.</p><p>El código de abajo crea un endpoint para la ruta <code>/api</code>.</p><p>Si nuestra app realiza una petición GET a esa ruta, respondemos (usando <code>res</code>, que significa respuesta) con nuestros datos JSON:</p><pre><code class="language-js">// server/index.js
...

app.get("/api", (req, res) =&gt; {
  res.json({ message: "Hola desde el servidor!" });
});

app.listen(PORT, () =&gt; {
  console.log(`Servidor escuchando en el puerto: ${PORT}`);
});</code></pre><p>Nota: Asegúrate de posicionar esto previo a la función <code>app.listen</code>.</p><p>Ya que hemos realizado cambios a nuestro código Node, necesitaremos reiniciar nuestro servidor.</p><p>Para este fin, termina el "start script" presionando <code>Command/Ctrl + C</code>. Luego lo reiniciaremos usando <code>npm start</code>, nuevamente, desde el terminal.</p><p>Y para probar esto podemos simplemente visitar <code>http://localhost:3001/api</code> en nuestro navegador web y ver en la pantalla el mensaje:</p><figure class="kg-card kg-image-card"><img src="https://reedbarger.nyc3.digitaloceanspaces.com/how-to-create-a-react-app-with-a-node-backend/clip-2.gif" class="kg-image" alt="Clip 2" width="600" height="400" loading="lazy"></figure><h2 id="paso-3-crear-el-cliente-react">Paso 3: Crear el cliente React </h2><p>Luego de haber creado el backend (servidor), vayamos al frontend (cliente).</p><p>Abre otra pestaña en la terminal y utiliza el comando <code>create-react-app</code> para crear un nuevo proyecto React con el nombre <code>client</code>:</p><pre><code class="language-bash">npx create-react-app client</code></pre><p>Luego de esto tendremos una aplicación React con todas sus dependencias instaladas.</p><p>El único cambio que tenemos que hacer es agregar una propiedad llamada <code>proxy</code> a nuestro archivo <code>package.json</code>.</p><p>Esto nos permitirá realizar peticiones a nuestro servidor Node sin tener que proporcionar el origen en el que se encuentra corriendo (http://localhost:3001) cada vez que le hagamos una petición de red: </p><pre><code class="language-bash">// client/package.json

...
"proxy": "http://localhost:3001",
...</code></pre><p>Luego podemos iniciar nuestra app React al ejecutar el script "start", que es el mismo para nuestro servidor Node. Primero asegúrate de entrar en la carpeta <code>/client</code> recién creada usando <code>cd client</code> en el terminal - luego ya podrás ejecutar el comando <code>npm start</code> correctamente.</p><p>Luego de esto la app iniciará en <code>localhost:3000</code>:</p><pre><code class="language-bash">cd client
npm start

Compiled successfully! 

You can now view client in the browser.

Local:            http://localhost:3000</code></pre><figure class="kg-card kg-image-card"><img src="https://reedbarger.nyc3.digitaloceanspaces.com/how-to-create-a-react-app-with-a-node-backend/clip-3.gif" class="kg-image" alt="Clip 3" width="600" height="400" loading="lazy"></figure><h2 id="paso-4-realiza-peticiones-http-desde-react-a-node">Paso 4: Realiza peticiones HTTP desde React a Node</h2><p>Ahora que tenemos una aplicación React en funcionamiento, queremos usarla para interactuar con nuestra API.</p><p>Veamos como podemos traer datos desde el endpoint <code>/api</code> que hemos creado anteriormente.</p><p>Para hacer esto podemos dirigirnos al componente <code>App.js</code> dentro de nuestra carpeta <code>src</code> y hacer una petición HTTP utilizando <code>useEffect</code>.</p><p>Haremos una petición GET simple a nuestro backend usando el Fetch API y luego tendremos nuestros datos de regreso en formato JSON.</p><p>Una vez que tengamos los datos, obtendremos la propiedad con el nombre "message" (para poder tomar el saludo que hemos enviado desde el servidor) y entonces ponerlo en una variable de "estado" ( state ) llamada <code>data</code>.</p><p>Esto nos permitirá mostrar ese mensaje en nuestra página (asumiendo que sí lo tenemos). Estamos usando un condicional en nuestro JSX para decir que si nuestros datos no están disponibles se muestre el texto "Loading...".</p><pre><code class="language-js">// client/src/App.js

import React from "react";
import logo from "./logo.svg";
import "./App.css";

function App() {
  const [data, setData] = React.useState(null);

  React.useEffect(() =&gt; {
    fetch("/api")
      .then((res) =&gt; res.json())
      .then((data) =&gt; setData(data.message));
  }, []);

  return (
    &lt;div className="App"&gt;
      &lt;header className="App-header"&gt;
        &lt;img src={logo} className="App-logo" alt="logo" /&gt;
        &lt;p&gt;{!data ? "Loading..." : data}&lt;/p&gt;
      &lt;/header&gt;
    &lt;/div&gt;
  );
}

export default App;</code></pre><figure class="kg-card kg-image-card"><img src="https://reedbarger.nyc3.digitaloceanspaces.com/how-to-create-a-react-app-with-a-node-backend/clip-4.gif" class="kg-image" alt="Clip 5" width="600" height="400" loading="lazy"></figure><h2 id="paso-5-despliega-tu-aplicaci-n-a-la-web-con-heroku">Paso 5: Despliega tu aplicación a la web con Heroku</h2><p>Finalmente, desplegaremos nuestra aplicación a la web.</p><p>Primero, dentro de la carpeta <code>/client</code> de nuestro proyecto, asegúrate de remover el repositorio Git que se inicializa automáticamente al usar el comando <code>create-react-app</code>. </p><p>Esto es esencial para desplegar nuestra aplicación, ya que vamos a configurar un repositorio Git en el directorio principal de nuestro proyecto ( <code>react-node-app</code>), es decir, no en <code>/client</code>:</p><pre><code class="language-bash">cd client
rm -rf .git</code></pre><p>Cuando desplegamos nuestro backend Node (servidor) y nuestro frontend React (cliente) van a ser servidos desde el mismo dominio (i.e. mycoolapp.herokuapp.com).</p><p>Cómo nuestras peticiones son manejadas por nuestra API Node, necesitamos escribir algo de código que mostrará nuestro app React cuando sea visitado por nuestros usuarios (por ejemplo, cuando visiten la página de inicio).</p><p>Podemos implementar esto en <code>server/index.js</code> agregando el siguiente código:</p><pre><code class="language-js">// server/index.js
const path = require('path');
const express = require('express');

...

// Hacer que node sirva los archivos de nuestro app React
app.use(express.static(path.resolve(__dirname, '../client/build')));

// Manejar las peticiones GET en la ruta /api
app.get("/api", (req, res) =&gt; {
  res.json({ message: "Hello from server!" });
});

// Todas las peticiones GET que no hayamos manejado en las líneas anteriores retornaran nuestro app React
app.get('*', (req, res) =&gt; {
  res.sendFile(path.resolve(__dirname, '../client/build', 'index.html'));
});</code></pre><p>Lo que este código hará primero es darle acceso a Node a nuestro proyecto React compilado usando la función <code>express.static</code> para archivos estáticos.</p><p>Y si una petición GET llega que no esté contemplada para su manejo en nuestra ruta <code>/api</code>, nuestro servidor responderá con nuestro app React.</p><p><strong>Este código permite que nuestra app React y Node sea desplegada en el mismo dominio.</strong></p><p>Entonces podremos indicar a nuestro app (Node) como hacerlo, agregando un script <code>build</code> a nuestro archivo <code>package.json</code> con el propósito de que compile nuestra app para producción:</p><pre><code class="language-json">// server/package.json

...
"scripts": {
    "start": "node server/index.js",
    "build": "cd client &amp;&amp; npm install &amp;&amp; npm run build"
  },
...</code></pre><p>También recomendaría agregar un campo llamado "engines" (motores), dónde querrás especificar la versión de Node que estás usando para compilar tu proyecto. Esto será utilizado para el despliegue.</p><p>Puedes conocer la versión que estás usando de Node al ejecutar el comando <code>node -v</code> y puedes escribir el resultado en la propiedad "engines" (ejemplo v. 14.14.4):</p><pre><code class="language-json">// server/package.json

"engines": {
  "node": "tu-número-de-versión-node"
}</code></pre><p>Luego de esto estaremos listos para desplegar usando Heroku, así que asegúrate de tener una cuenta en <a href="https://heroku.com">Heroku.com</a>.</p><p>Una vez que hayas iniciado sesión en Heroku y te encuentres viendo tu panel de control, seleccionarás: "New &gt; Create New App" y proporcionarás un nombre único para tu app.</p><p>Luego de esto, querrás instalar el Heroku CLI (Interfaz de línea de comandos) para que puedas desplegar tu aplicación cuando sea que realices cambios usando Git. Podemos instalar el CLI ejecutando el siguiente comando:</p><pre><code class="language-bash">sudo npm i -g heroku</code></pre><p>Una vez instalado, podrás iniciar sesión en Heroku con el CLI usando el comando <code>heroku login</code>:</p><pre><code class="language-bash">heroku login

Press any key to login to Heroku (Presiona cualquier tecla para iniciar sesión en Heroku.</code></pre><p>Ya que has iniciado sesión en Heroku desde el CLI necesitas seguir las instrucciones de despliegue para nuestra recién creada aplicación desde la pestaña "Deploy".</p><p>Los siguientes comandos inicializarán un nuevo repositorio Git para nuestro proyecto, agregarán tus archivos ahí, realizarán un commit y agregarán un Git remote para Heroku.</p><pre><code>git init
heroku git:remote -a inserta-el-nombre-de-tu-app-aqui
git add .
git commit -am "Desplegar app en Heroku"</code></pre><p>Luego el último paso es publicar nuestra aplicación subiéndola ( <code>git push</code> )al remoto Git de Heroku que justo hemos agregado usando:</p><pre><code class="language-bash">git push heroku master</code></pre><p>¡Felicitaciones! Nuestra aplicación full-stack Node-React ya está en línea! ?</p><figure class="kg-card kg-image-card"><img src="https://reedbarger.nyc3.digitaloceanspaces.com/how-to-create-a-react-app-with-a-node-backend/clip-5.gif" class="kg-image" alt="Clip 5" width="600" height="400" loading="lazy"></figure><p>Cuando quieras realizar cambios a tu aplicación en futuras ocasiones (y desplegarlas/publicarlas), solo tienes que usar Git para agregar tus archivos, realizar un commit y subirlos al repositorio remoto Heroku:</p><pre><code class="language-bash">git add .
git commit -m "my commit message"
git push heroku master</code></pre> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Tutorial de CSS Flexbox y CSS Grid: Cómo crear una pagina de inicio responsivo con HTML y CSS ]]>
                </title>
                <description>
                    <![CDATA[ Author artículo original: Kingsley Ubah [https://www.freecodecamp.org/news/author/ubahthebuilder/]  Articulo original: CSS Flexbox and Grid Tutorial – How to Build a Responsive Landing Page with HTML and CSS [https://www.freecodecamp.org/news/css-flexbox-and-grid-tutorial/]. Traducido y adaptado por Israel Palma [/espanol/news/author/israel/] En este tutorial vamos a crear una página de inicio sencilla para una plataforma educativa llamada ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/tutorial-de-css-flexbox-y-css-grid-como-crear-una-pagina-de-inicio-responsivo-con-html-y-css/</link>
                <guid isPermaLink="false">616f344c5658740999353023</guid>
                
                    <category>
                        <![CDATA[ CSS ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Palma ]]>
                </dc:creator>
                <pubDate>Mon, 30 May 2022 04:04:23 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2022/05/SkilllzLanding.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><strong>Author artículo original:</strong> <a href="https://www.freecodecamp.org/news/author/ubahthebuilder/">Kingsley Ubah</a> <br><strong>Articulo original:</strong> <a href="https://www.freecodecamp.org/news/css-flexbox-and-grid-tutorial/">CSS Flexbox and Grid Tutorial – How to Build a Responsive Landing Page with HTML and CSS</a>.<br><strong>Traducido y adaptado por </strong><a href="https://www.freecodecamp.org/espanol/news/author/israel/">Israel Palma</a></p><p>En este tutorial vamos a crear una página de inicio sencilla para una plataforma educativa llamada <strong>Skillz</strong>.</p><p>Aquí aprenderás como usar e implementar CSS Flexbox y CSS Grid para alinear contenido. &nbsp;También cubriremos muchos otros conceptos de CSS y finalmente aprenderemos a hacer la página responsiva para que trabaje en todos los tamaños de pantallas.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/ezgif.com-gif-maker.gif" class="kg-image" alt="ezgif.com-gif-maker" width="600" height="400" loading="lazy"></figure><p>Este tutorial se divide en cinco partes:</p><ul><li>Como construir la barra de navegación.</li><li>Como crear la sección showcase (escaparate)</li><li>Como construir la sección de la parte inferior</li><li>Como crear la sección del pié de página</li><li>Cómo hacer la página responsiva</li></ul><p>Cada una de estas secciones te enseñará algún concepto CSS nuevo, así como herramientas y habilidades de desarrollo CSS. Comencemos!</p><h2 id="como-crear-el-html-inicial-boilerplate-"><strong>Como crear el <strong>HTML</strong> inicial (<strong>Boilerplate</strong>)<strong> </strong></strong></h2><p>Si tienes "emmet" instalado en tu IDE (entorno de desarrollo o editor de texto), puedes generar el "boilerplate" HTML (inicial) para tu proyecto al escribir &nbsp;<code>!</code> y pulsando &nbsp;<code>enter</code> o <code>tab</code> en tu teclado.</p><p>Sino puedes copiar este "boilerplate" y pegarlo en tu editor de código:</p><pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
  &lt;meta charset="UTF-8"&gt;
  &lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&gt;
  &lt;meta http-equiv="X-UA-Compatible" content="ie=edge"&gt;
  &lt;title&gt;Document&lt;/title&gt;
  &lt;link rel="stylesheet" href="styles.css"&gt;
  &lt;link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ=="
  crossorigin="anonymous" referrerpolicy="no-referrer" /&gt;
&lt;/head&gt;
&lt;body&gt;
 
&lt;/body&gt;
&lt;/html&gt;</code></pre><h3 id="c-mo-usar-los-conos-font-awesome"><strong>Cómo usar los íconos Font Awesome </strong></h3><p>Cómo puedes ver en una de las capturas de pantalla, usaremos algunos íconos fuente para darle una mejor apariencia a nuestra sección de servicios. </p><p>Para esto, usaremos "font awesome" desde una CDN (Content Delivery Network - red de distribución de contenido). Si creaste el "boilerplate" HTML copia la siguiente etiqueta &nbsp;<code>link</code> y pégala dentro de la etiqueta <code>head</code> :</p><figure class="kg-card kg-code-card"><pre><code class="language-html">&lt;link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.15.4/css/all.min.css" integrity="sha512-1ycn6IcaQQ40/MKBW2W4Rhis/DbILU74C1vSrLJxCq57o941Ym01SwNsOMqvEBFlcgUa6xLiPY/NS5R+E6ztJQ=="
  crossorigin="anonymous" referrerpolicy="no-referrer" /&gt;</code></pre><figcaption>Esto te permitirá utilizar los íconos "Font Awesome" ent tu proyecto</figcaption></figure><h2 id="empecemos-"><strong>Empecemos!</strong></h2><p>En primer lugar asegurate que tu archivo de estilos (.css) esté apropiadamente vinculado con tu página HTML.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/test.png" class="kg-image" alt="test" width="600" height="400" loading="lazy"></figure><h2 id="como-construir-la-barra-de-navegaci-n"><strong>Como construir la barra de navegación</strong></h2><p>La barra de navegación incluirá el nombre de nuestro sitio web además de dos enlaces de navegación: &nbsp;<code>Log in</code> (iniciar sesión) y <code>check courses</code> (revisar cursos).</p><p>Esté es el "markup" (código HTML) para nuestra barra de navegación:</p><pre><code class="language-js">&lt;div class="navbar"&gt;
        &lt;div class="container flex"&gt;
          &lt;h1 class="logo"&gt;Skilllz&lt;/h1&gt;
            &lt;nav&gt;
              &lt;ul&gt;
                &lt;li class="nav"&gt;&lt;a class="outline" href=""&gt;Log in&lt;/a&gt;&lt;/li&gt;
                &lt;li class="nav"&gt;&lt;a href="" class="outline"&gt;Check courses&lt;/a 				&lt;/li&gt;
              &lt;/ul&gt;
            &lt;/nav&gt;
        &lt;/div&gt;
      &lt;/div&gt;</code></pre><p>En el <code>div</code> que envuelve los elementos en esta sección (la barra de navegación), registramos el contenedor y la clase (css) flex.</p><ul><li><code>.container</code>: usaremos esta clase utilitaria en cada sección para asegurarnos que los elementos internos no excedan cierto ancho, el cual especificaremos en CSS</li><li><code>.flex</code>: usaremos esta clase utilitaria para mostrar los elementos hijos alineados horizontalmente (lado-a-lado) usando CSS Flexbox.</li></ul><p>Dentro del <code>div</code> tenemos un <code>h1</code>con la clase <code>logo</code> y dos enlaces de navegación <code>li&gt;a</code> con la clase <code>outline</code> respectivamente.</p><p>En este punto, nuestra página lucirá plana y simple, justo así:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/navbarHTML1.png" class="kg-image" alt="navbarHTML1" width="600" height="400" loading="lazy"><figcaption>No CSS yet</figcaption></figure><h3 id="c-mo-aplicar-estilo-css-a-nuestra-p-gina"><strong>Cómo aplicar estilo CSS a nuestra página</strong></h3><p>Ahora tenemos que aplicar algunas reglas CSS para estilizar nuestra sección de navegación de la manera que mejor nos parezca. Lo que queremos hacer primero es establecer los estilos básicos para nuestra página web con el código siguiente:</p><pre><code class="language-css">/* Sobrescribe el estilo por defecto y establece el padding y el margen a cero */

* {
  box-sizing: border-box;
  padding: 0;
  margin: 0
}

/* Texto color blanco en todas partes */

body {
  font-family: "lato", sans-serif;
  color: white;
}

/* Hacer todo el texto de los links negro y sin decoración*/
a {
  color: black;
  text-decoration: none;
}


h1 {
  font-size: 30px;
  font-weight: 600;
  margin: 10px 0;
  line-height: 1.2;
}


h2 {
  font-size: 25px;
  font-weight: 300;
  margin: 10px 0;
  line-height: 1.2;
}

p {
  font-size: 30px;
}

/* Todas las imágenes deben ser del mismo tamañño que su contenedor*/
img {
  width: 100%;
}

/* Remover el estilo a los elementos de una lista */
li {
  list-style-type: none;
}



p {
  font-size: 20px;
  margin: 10px 0;
}

</code></pre><p>Con estos estilos por defecto aplicados nuestra página se verá así:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/navbarHTML2.png" class="kg-image" alt="navbarHTML2" width="600" height="400" loading="lazy"></figure><p>A continuación necesitamos definir el estilo para nuestra clase css "container":</p><pre><code class="language-css">/* Centra el elemento y establece un ancho máximo y se asegura que los elementos puedan fluir através*/

.container {
  margin: 0 auto;
  max-width: 1200px;
  overflow: visible;
}</code></pre><p>Ahora, nuestro contenido no excederá el ancho máximo especificado. </p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/navbarHTML3.png" class="kg-image" alt="navbarHTML3" width="600" height="400" loading="lazy"></figure><p>Luego de esto, necesitamos definir el color purpura para el fondo de nuestra sección "navbar":</p><pre><code class="language-css">/* Aplica el color de fondo, altura y "padding"*/

.navbar {
  background-color: purple;
  height: 70px;
  padding: 0 30px;
}</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/navbarHTML4.png" class="kg-image" alt="navbarHTML4" width="600" height="400" loading="lazy"></figure><p>Enseguida seleccionamos sólo el elemento <code>h1</code> dentro del <code>navbar</code> y definimos los siguientes estilos:</p><pre><code class="language-css">/* Establece el tamaño de la fuente (font size), reduce el peso de loa fuente (font-weight), agrega margen y alto de línea (line height) */

.navbar h1 {
  font-size: 30px;
  font-weight: 300;
  margin: 10px 0;
  line-height: 1.2;
}</code></pre><p>Aplicando este estilo, nuestro encabezado <code>h1</code> &nbsp;se verá así:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/navbarH5.png" class="kg-image" alt="navbarH5" width="600" height="400" loading="lazy"></figure><p>Ahora necesitamos mostrar ambos elementos hijos dentro del contenedor <code>h1</code> y <code>nav</code> una al lado del otro usando Flexbox.</p><pre><code class="language-css">.navbar .flex {
  display: flex;
  justify-content: space-between;
  align-items: center;
  height: 100%;
}</code></pre><p>Primero, damos el valor <code>flex</code> para "display-mode". Esto alineara los elementos uno al lado del otro por de forma automática (<strong>por default</strong>). &nbsp;</p><p>Entonces justificamos el contenido, agregando espacio considerable entre cada elemento usando el valor de <code>space-between</code>. Alineamos los elementos para que aparezcan al centro del contenedor y darle una altura que cubra el alto completo del elemento que lo contiene.</p><p>Así es como nuestra página se debe ver:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/navrbarH6.png" class="kg-image" alt="navrbarH6" width="600" height="400" loading="lazy"><figcaption>Cool verdad?</figcaption></figure><p>Sin embargo, tampoco queremos que ambos enlaces de navegación estén apilados uno sobre otro. En vez de eso, querem0s que aparezcan lado a lado. Adivinas como haríamos eso? Con Flexbox!</p><pre><code class="language-css">.navbar ul {
  display: flex;
}

/* Cambia el color de ambos enlaces a blanco, agrega padding entre si y margen también */

.navbar a {
  color: white;
  padding: 9px;
  margin: 0 10px;
}</code></pre><p>Nuestra página ahora se ve así:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/navbarH7.png" class="kg-image" alt="navbarH7" width="600" height="400" loading="lazy"><figcaption>El poder de CSS flexbox</figcaption></figure><p>Si haz visto el breve video introductorio, notarás que cuando sea que yo paso el ratón sobre los enlaces el color del texto cambia a una sombra púrpura y un borde sólido se muestra debajo.</p><p>Podemos implementar esta transición usando el pseudo-elemento CSS <code>:hover</code> :</p><pre><code class="language-css">.navbar a:hover {
  color: #9867C5;
  border-bottom: 3px solid #9867C5;
}</code></pre><p>Ahora mira esto:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/ezgif.com-gif-maker--1-.gif" class="kg-image" alt="ezgif.com-gif-maker--1-" width="600" height="400" loading="lazy"><figcaption>Efecto hover en los enlaces.</figcaption></figure><p>Y con eso hemos llegado al fin de la sección navbar (barra de navegación).</p><h2 id="como-crear-el-rea-de-presentaci-n"><strong>Como crear el área de presentación</strong></h2><p>El area de presentación es donde se va a ubicar el texto del encabezado, el texto de soporte, un formulario para dar de alta a nuevos usuario y también la imagen de encabezado.</p><p>Esta sección va a estar dividida en dos: la del lado izquierdo y el derecho. Dicho de otra forma, será mostrado como una retícula de dos unidades. </p><p>Aquí está el código HTML (markup) para esta sección:</p><pre><code class="language-html">&lt;section class="showcase"&gt;
        &lt;div class="container"&gt;
            &lt;div class="grid"&gt;
              &lt;div class="grid-item-1"&gt;
                &lt;div class="showcase-text"&gt;
                  &lt;h1&gt;Aprende cualquier habilidad digital que elijas, hoy!&lt;/h1&gt;
                  &lt;p class="supporting-text"&gt; Más de 30,000 estudiantes están aprendiendo esto.&lt;/p&gt;
                &lt;/div&gt;
                &lt;div class="showcase-form"&gt;
                  &lt;form action=""&gt;
                    &lt;input type="email" placeholder="Ingresa tu correo electrónico"&gt;
                    &lt;input type="submit" class="btn" value="Empieza a aprender"&gt;
                  &lt;/form&gt;
                  &lt;p class="little-info"&gt;Prueba nuestros cursos gratuitos&lt;/p&gt;
                &lt;/div&gt;
              &lt;/div&gt;

              &lt;div class="grid-item-2"&gt;
                &lt;div class="image"&gt;
                  &lt;img src="./images/transparent.png" alt=""&gt;
                &lt;/div&gt;
              &lt;/div&gt;
           &lt;/div&gt;

        &lt;/div&gt;
      &lt;/section&gt;</code></pre><p>En este punto nuestra app se verá todavía un poco desaliñada:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/showcaseH1.png" class="kg-image" alt="showcaseH1" width="600" height="400" loading="lazy"></figure><h3 id="como-aplicar-estilos-css-a-nuestro-rea-de-presentaci-n"><strong>Como aplicar estilos CSS a nuestro área de presentación</strong></h3><p>Primero, definimos la altura de la sección de área de presentacion así como también el color de fondo:</p><pre><code class="language-css">.showcase {
  height: 300px;
  background-color: purple;
}</code></pre><p>Nuestra aplicación ahora se ve así:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/showcaseH2.png" class="kg-image" alt="showcaseH2" width="600" height="400" loading="lazy"><figcaption>Still messy</figcaption></figure><blockquote>NOTA: cambié el color del <code>h1</code> a blanco.</blockquote><p>Enseguida, aplicamos los siguientes estilos:</p><pre><code class="language-css">/* Añade margen bajo el texto */
.showcase p {
  margin-bottom: 30px;
}

/* Añade una sombra bajo la imágen */
.showcase img {
  box-shadow: 7px 7px 7px rgba(0, 0, 0, 0.2);
}

/* Añade algo de padding al contenido del formulario */
.showcase-form {
  padding-left: 7px;
}</code></pre><p>Esto nos trae al tema principal. Si recuerdas, dije que crearíamos dos secciones (retículas) dentro del contenedor del área de presentación. Con la clase "grid" (retícula) aplicada al contenedor vamos a alinear el contenido utilizando CSS grid display de la siguiente manera:</p><pre><code class="language-css">.grid {
  overflow: visible;
  display: grid;
  grid-template-columns: 60% 40%;
}</code></pre><p>Esto creará dos columnas dentro del contenedor para el área de presentación. La primera parte tomará hasta 60% del contenedor y la segunda parte tomará el 40% restante.</p><p>El <code>overflow: visible</code> asegurará que la imagen fluya hacia afuera del contenedor (en caso de ser de mayor tamaño).</p><p>Nuestra app se verá así.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/showcaseH3.png" class="kg-image" alt="showcaseH3" width="600" height="400" loading="lazy"></figure><p>Enseguida necesitaremos definir algo de espacio entre el área de navegación (navigation) y el área de presentación.</p><pre><code class="language-css">.grid-item-1,
.grid-item-2 {
  position: relative;
  top: 50px;
}</code></pre><p>Como consecuencia ahora tiene un poco mas de espaciado:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/showcaseH4.png" class="kg-image" alt="showcaseH4" width="600" height="400" loading="lazy"></figure><p>Ahora necesitamos estilizar ambos elementos "input" de nuestro formulario porque aún no tienen una buena apariencia. Seleccionamos el primer <code>&lt;input /&gt;</code> por su tipo (email) y el segundo usando la clase CSS <code>btn</code>.</p><pre><code class="language-css">.showcase input[type='email'] {
  padding: 10px 70px 10px 0;
  font-size: 14px;
  border: none;
  border-radius: 6px;
  padding-left: 6px;
}

.btn {
  border-radius: 6px;
  padding: 12px 20px;
  background: #9867C5;
  border: none;
  margin-left: 10px;
  color: white;
  font-size: 16px;
  cursor: pointer;
  box-shadow: 0 10px 10px rgba(0, 0, 0, 0.2);
}</code></pre><p>Estos estilos CSS transformarán ambos "inputs" del formulario en esto:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/showcaseH5-1.png" class="kg-image" alt="showcaseH5-1" width="600" height="400" loading="lazy"><figcaption>Inputs del formulario ya estilizados.</figcaption></figure><p>También debemos cambiar la fuente del texto:</p><pre><code class="language-css">.showcase-form {
  margin: auto;
}

/* Change typeface and its size */
.little-info {
  font-size: 15px;
  font-family: "poppins", sans-serif;

}</code></pre><p>Así se verá finalmente la sección de área de presentación:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/showcaseH7.png" class="kg-image" alt="showcaseH7" width="600" height="400" loading="lazy"><figcaption>Apariencia final de la sección de escaparate (showcase)</figcaption></figure><p>Es todo en esta sección!</p><h2 id="c-mo-hacer-la-parte-inferior-de-la-p-gina-"><strong>Cómo hacer la parte inferior de la página.</strong></h2><p>La parte inferior de la página contendrá dos secciones, la sección de <strong>estadísticas</strong> y la sección de testimoniales.</p><p>El elemento contenedor para la sección de estadísticas que mostrará los servicios ofrecidos por <strong>Skillz </strong>estará conformado por tres <code>div</code>, cada uno de los cuales tendrá dentro de sí un ícono Font Awesome, un elemento <code>h3</code> con clase <code>title</code>, y un párrafo <code>p</code> con clase <code>text</code>. </p><p>El elemento contenedor para los testimonios llevará tres testimonios de personas que aprendieron usando Skillz. Tomé las fotos de unsplash.</p><h3 id="c-mo-crear-la-secci-n-de-estad-sticas"><strong>Cómo crear la sección de estadísticas</strong></h3><p>Primero, vamos a trabajar en la sección de estadísticas. El texto es uno ficticio de 'lorem50' (50 palabras de "lorem ipsum") para ser utilizado como relleno para este demo.</p><p>Aquí puedes ver el "markup" HTML:</p><pre><code class="language-html">&lt;div class="lower-container container"&gt;
      &lt;section class="stats"&gt;
        &lt;div class="flex"&gt;
          &lt;div class="stat"&gt;
            &lt;i class="fa fa-folder-open fa-2x" aria-hidden="true"&gt;&lt;/i&gt;
            &lt;h3 class="title"&gt;Over 300 available courses&lt;/h3&gt;
            &lt;p class="text"&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
              Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.&lt;/p&gt;
          &lt;/div&gt;
          &lt;div class="stat"&gt;
            &lt;i class="fa fa-graduation-cap fa-2x" aria-hidden="true"&gt;&lt;/i&gt;
            &lt;h3 class="title"&gt;Free certificate offered on all courses&lt;/h3&gt;
            &lt;p class="text"&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
              Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.&lt;/p&gt;
          &lt;/div&gt;
          &lt;div class="stat"&gt;
            &lt;i class="fa fa-credit-card-alt fa-2x" aria-hidden="true"&gt;&lt;/i&gt;
            &lt;h3 class="title"&gt;Book 1on1 session for as low as $5&lt;/h3&gt;
            &lt;p class="text"&gt;Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
              Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/section&gt;</code></pre><p>Esta sección será mostrada como una página en blanco. Esto debido a que hemos definido el color blanco como el color para todo el texto del elemento "body" de nuestro documento. Así que tendremos que estilizarlo al color apropiado. </p><h3 id="c-mo-aplicar-estilos-css-a-la-secci-n-de-estad-sticas-"><strong>Cómo aplicar estilos CSS a la sección de estadísticas.</strong></h3><p>Primero necesitamos aplicar los siguientes estilos:</p><pre><code class="language-css">/* Centra el conetenedor, aplica un ancho máximo*/
.lower-container {
  margin: 120px auto;
  padding: 0;
  max-width: 1400px;
}


/* Apunta a todos los elementos h3 con clase CSS title */
.title {
  color: black;
  font-size: 20px;
  text-align: left;
  padding-left: 10px;
  padding-top: 10px;
}

/* Apunta a todos los parrafos con la clase CSS text */
.text {
  color: black;
  font-size: 19px;
  width: 100%;
  padding: 10px;
  margin: 0, 20px;
  text-align: justify;
}</code></pre><p>Ahora esto hará que nuestro texto sea visible:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/lower1.png" class="kg-image" alt="lower1" width="600" height="400" loading="lazy"></figure><p>Notarás que los íconos-fuente de Font Awesome no son visibles. Trabajaremos en eso muy pronto. </p><p>Pero antes de eso, necesitaremos hacer algo importante. Sí tenemos la intención de que los 3 <code>div</code> &nbsp;de la sección de estadísticas estén alineados de forma horizontal (lado a lado). Para lograr eso, usaremos una vez más CSS Flexbox:</p><pre><code class="language-css">/* Mostrar horizontalmente, poner un poco de espacio alrededor */
.flex {
  display: flex;
  justify-content: space-around;
}

/* Agregar algo de padding alrededor del contenedor. Alinear el texto al centro */
.stats {
  padding: 45px 50px;
  text-align: center;
}

/* Aplicar margen y ancho */
.stat {
  margin: 0 30px;
  text-align: center;
  width: 800px;
}</code></pre><p>Así es como se verá nuestra app ahora:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/lower2.png" class="kg-image" alt="lower2" width="600" height="400" loading="lazy"></figure><p>Aún sin íconos? Hora de arreglarlo!</p><pre><code class="language-css">.stats .fa {
  color: purple;
}</code></pre><p>y voilà!</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/lower4.png" class="kg-image" alt="lower4" width="600" height="400" loading="lazy"></figure><h3 id="como-crear-la-secci-n-de-testimonios"><strong>Como crear la sección de testimonios</strong></h3><p>La segunda sección dentro del contenedor <code>div</code> de la parte inferior de la página es la sección de testimonios. Esta sección estará compuesta de tres tarjetas, cada una de las cuales contiene la imagen de la persona (recortada dentro de un círculo), su nombre y su testimonio personal.</p><p>Aquí esta el HTML para eso:</p><pre><code class="language-html">&lt;section class="testimonials"&gt;
      &lt;div class="container"&gt;
        &lt;div class="testimonial grid-3"&gt;
          &lt;div class="card"&gt;
            &lt;div class="circle"&gt;
              &lt;img src="./images/4.jpg" alt=""&gt;
            &lt;/div&gt;
            &lt;h3&gt;Aston&lt;/h3&gt;
            &lt;p&gt;He aprendido desarrollo web usando esta plataforma y diré que es la mejor plataforma para aprender. Definitivamente vale la pena la inversión!&lt;/p&gt;
          &lt;/div&gt;
          &lt;div class="card"&gt;
            &lt;div class="circle"&gt;
              &lt;img src="./images/5.jpg" alt=""&gt;
            &lt;/div&gt;
            &lt;h3&gt;Beth&lt;/h3&gt;
            &lt;p&gt;He aprendido redacción usando esta plataforma y diré que es la mejor plataforma para aprender. Definitivamente vale la pena la inversión!&lt;/p&gt;
          &lt;/div&gt;
          &lt;div class="card"&gt;
            &lt;div class="circle"&gt;
              &lt;img src="./images/6.jpg" alt=""&gt;
            &lt;/div&gt;
            &lt;h3&gt;Chris&lt;/h3&gt;
            &lt;p&gt;He aprendido marketing de afiliados usando esta plataforma y diré que es la mejor plataforma para aprender. Definitivamente vale la pena la inversión!&lt;/p&gt;
          &lt;/div&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/section&gt;</code></pre><h3 id="c-mo-aplicarle-estilos-css"><strong>Cómo aplicarle estilos CSS</strong></h3><p>Primero establecemos el color del texto a negro para que sea visible:</p><pre><code class="language-css">.testimonial {
  color: black;
  padding: 40px;
}</code></pre><p>Cuando lo aplicamos, debe hacer que el texto sea visible y agregar algo de padding a la sección:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/testi1.png" class="kg-image" alt="testi1" width="600" height="400" loading="lazy"></figure><p>Enseguida, damos a la imagen la altura suficiente para ocupar todo el alto de su contenedor padre:</p><pre><code class="language-css">
/* Envuelve la imagen dentro de una figura circular y define su altura para que tome todo el alto de su elemento padre */

.testimonial img {
    height: 100%;
    clip-path: circle();
}

/* Alinea el texto al centro */

.testimonial h3{
  text-align: center;
}

</code></pre><p>Si checas el diseño final en el gif, notarás que las tres tarjetas testimoniales estarán alineadas lado a lado en la misma fila.</p><p>Así que necesitaremos crear un div de tres columnas equidistantes usando un arreglo CSS grid.</p><pre><code class="language-css">/* Crear un grid de tres columnas equidistantes. Definir un espaciado de 40px entre ellas */

.grid-3 {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  gap: 40px;
}


/* Crear una tarjeta en blanco con sombreado alrededor */
.card {
  padding: 10px;
  background-color: white;
  border-radius: 10px;
  box-shadow: -7px -7px 20px rgba(0, 0, 0, 0.2),
               7px  7px 20px rgba(0, 0, 0, 0.2)
}</code></pre><p>Con todos estos estilos aplicados, la sección de testimoniales ahora se debe ver así:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/testi2.png" class="kg-image" alt="testi2" width="600" height="400" loading="lazy"></figure><p>Finalmente, daremos estilo al <code>div</code> circular y lo colocaremos relativo al borde superior de la tarjeta usando CSS:</p><pre><code class="language-css">.circle {
    background-color: transparent;
    border:3px solid purple;
    height:90px;
    position: relative;
    top: -30px;
    left: 120px;
    border-radius:50%;
    -moz-border-radius:50%;
    -webkit-border-radius:50%;
    width:90px;
}</code></pre><p>Y aquí verás como todo esto se verá en el navegador:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/testi4.png" class="kg-image" alt="testi4" width="600" height="400" loading="lazy"><figcaption>Apariencia preliminar</figcaption></figure><p>Muy bien, ahora estamos listos para movernos a la sección del "footer" (pie de página). Luego aprenderemos como hacer que el sitio sea responsivo.</p><h2 id="c-mo-elaborar-la-secci-n-del-pi-de-p-gina"><strong>Cómo elaborar la sección del pié de página<strong> </strong></strong></h2><p>La parte final del proceso de creación de nuestra página es crear la sección del "footer". El pié de página comprenderá el texto de "copyright", tres enlaces de navegación adicionales y un grupo de íconos de medios sociales de Font Awesome.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/ezgif.com-gif-maker--2-.gif" class="kg-image" alt="ezgif.com-gif-maker--2-" width="600" height="400" loading="lazy"></figure><p>Este el el HTML para la sección del pié de página de nuestra página de inicio:</p><pre><code class="language-html">&lt;footer&gt;
   &lt;div class="container grid-3"&gt;
     &lt;div class="copyright"&gt;
       &lt;h1&gt;Skilllz&lt;/h1&gt;
       &lt;p&gt;Copyright &amp;copy; 2021&lt;/p&gt;
     &lt;/div&gt;
     &lt;nav class="links"&gt;
       &lt;ul&gt;
         &lt;li&gt;&lt;a href="" class="outline"&gt;Home&lt;/a&gt;&lt;/li&gt;
         &lt;li&gt;&lt;a href="" class="outline"&gt;Tutors&lt;/a&gt;&lt;/li&gt;
         &lt;li&gt;&lt;a href="" class="outline"&gt;Categories&lt;/a&gt;&lt;/li&gt;
       &lt;/ul&gt;
     &lt;/nav&gt;
     &lt;div class="profiles"&gt;
       &lt;a href=""&gt;&lt;em class="fab fa-twitter fa-2x"&gt;&lt;/em&gt;&lt;/a&gt;
       &lt;a href=""&gt;&lt;em class="fab fa-instagram fa-2x"&gt;&lt;/em&gt;&lt;/a&gt;
       &lt;a href=""&gt;&lt;em class="fab fa-facebook fa-2x"&gt;&lt;/em&gt;&lt;/a&gt;
       &lt;a href=""&gt;&lt;em class="fab fa-whatsapp fa-2x"&gt;&lt;/em&gt;&lt;/a&gt;
     &lt;/div&gt;
   &lt;/div&gt;
 &lt;/footer&gt;</code></pre><p>El pié de página se verá nada atractivo sin estilos CSS:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/footer-1.png" class="kg-image" alt="footer-1" width="600" height="400" loading="lazy"><figcaption>Aún sin CSS</figcaption></figure><p>Arreglemos eso.</p><h3 id="como-estilizar-el-pi-de-p-gina-footer-"><strong>Como estilizar el pié de página (f<strong>ooter</strong>)</strong></h3><p>Primero necesitamos asignar el color blanco para el fondo de la sección del "footer" (así como también para todos los links), de la siguiente forma:</p><pre><code class="language-css">/* Add padding around the footer as well */

footer {
  background-color: purple;
  padding: 20px 10px;
}

/* Sets all link texts to white and puts margin to the left and right */

footer a {
  color: white;
  margin: 0 10px;
}</code></pre><p>Ahora el pié de página (footer) se verá así:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/footer3.png" class="kg-image" alt="footer3" width="600" height="400" loading="lazy"><figcaption>Footer</figcaption></figure><p>Si revisas el primer gif, notarás que cuándo le paso el ratón por encima a cualquiera de los enlaces del "footer", su color cambia a una tonalidad más clara de púrpura y el borde se muestra debajo.</p><p>Podemos lograr esto usando un selector <code>:hover</code> :</p><pre><code class="language-css">footer a:hover {
  color: #9867C5;
  border-bottom: 2px solid #9867C5;
}</code></pre><p>Esto es todo para el "footer"!</p><h2 id="c-mo-definir-media-queries-para-hacer-la-p-gina-responsiva-"><strong>Cómo definir "Media Queries" para hacer la página responsiva.</strong></h2><p>Ahora es momento de hacer más responsiva nuestra "landing page". Cuándo se crea un sitio web es importante tener en mente que los usuarios verán el sitio desde distintos dispositivos. Por lo que es imperativo hacer responsivo el sitio para mejorar la experiencia de usuario en los múltiples formatos y tamaños de pantalla.</p><p>En nuestro CSS definiremos los "media queries" para establecer los breakpoints para los distintos anchos de pantalla y los diferentes dispositivos y relacionarlo con un grupo de reglas CSS para cada tamaño de pantalla.</p><h3 id="c-mo-dise-ar-para-tablets-y-pantallas-m-s-peque-as"><strong>Cómo diseñar para tablets y pantallas más pequeñas</strong></h3><p>Primero, optimizaremos la distribución de nuestro sitio para usuarios que lo visualicen desde una tablet. En nuestro CSS definiremos la siguiente regla:</p><pre><code class="language-css">/* Tablets y pantallas más pequeñas */

@media(max-width: 768px) {
  .grid,
  .grid-3 {
    grid-template-columns: 1fr;
  }</code></pre><p>Inicialmente hemos definido dos columnas para la clase <code>.grid</code> y 3 columnas para la clase <code>.grid-3</code>. Ahora, queremos asegurarnos que todos los elementos del grid abarquen una sola linea.</p><p>Cómo resultado, nuestro formulario e imagen que antes se mostraban lado-a-lado (horizontalmente) ahora se mostrará uno luego del otro (verticalmente), Así:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/resp1.png" class="kg-image" alt="resp1" width="600" height="400" loading="lazy"></figure><p>Enseguida, aplicaremos los siguientes reglas de estilo:</p><pre><code class="language-css">/* Alinear todo el texto al centro. Esto moverá todo el texto, incluyendo el formulario al centro.*/

.showcase {
    height: auto;
    text-align: center;
  }

/* Esto restablece el ancho del contendor de la imagen y agrega margen a la izquierda 
*/ 

.image {
    width: 600px;
    margin-left: 80px;
  }

/* Cambia las secciones de servicio de lado-a-lado para que cada una se posicione en una sóla linea. Centra el texto. */

.stats .flex {
    flex-direction: column;
  }

  .stats {
    text-align: center;
  }

/* Asegura que cada sección en las estadísticas no exceda el ancho del elemento padre. */

.stat {
    width: 100%;
    padding-right: 80px;
  }

/* Mueve el círculo al centro de la tarjeta  */

.circle {
      background-color: transparent;
      border:3px solid purple;
      height:90px;
      position: relative;
      top: -30px;
      left: 270px;
      border-radius:50%;
      -moz-border-radius:50%;
      -webkit-border-radius:50%;
      width:90px;
  }

</code></pre><p>Y voila. Nuestro sitio ahora funciona en tablets y pantallas más pequeñas.</p><p></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2021/09/ezgif.com-gif-maker--3--1.gif" class="kg-image" alt="ezgif.com-gif-maker--3--1" width="600" height="400" loading="lazy"><figcaption>The result</figcaption></figure><h3 id="c-mo-dise-ar-para-dispositivos-m-viles"><strong>Cómo diseñar para dispositivos móviles</strong></h3><p>Mucha gente podría visitar el sitio desde un dispositivo móvil, que típicamente tienen las pantallas más pequeñas. Debido a esto, crear una distribución para las pantallas móviles es muy importante.</p><pre><code class="language-css">/* Dispositivos móviles */
@media(max-width: 500px) {
  .navbar {
    height: 100px;
  }</code></pre><p>Primero incrementamos la altura de nuestra área de navegación. Dado que será vista desde una pantalla más pequeña, queremos que el area se muestre al usuario con más énfasis.</p><p>Luego, definimos las siguientes reglas de estilo:</p><pre><code class="language-css">/* Cambia la alineación. El logo del título se queda en la parte superior, los enlaces de navegación ahora se muestran debajo*/

.navbar .flex {
    flex-direction: column;
  }


/* Cuando pasamos encima el ratón, retienen el texto blanco y cambia el borde a negro */

  .navbar a:hover {
    color: white;
    border-bottom: 2px solid black;
  }


/* Establecer el color púrpura para el fondo de los enlaces de navegación, redondear las esquinas de los bordes y darle algo de espaciado*/

  .navbar ul {
    background: #9867C5;
    border-radius: 5px;
    padding: 10px 0;
  }


/* Alinear el texto al centro */

  .showcase {
    height: auto;
    text-align: center;
  }


/* Reducir el tamaño de la fuente */

.little-info {
    font-size: 13px;
  }


/* Reducir el ancho de la imágen */

  .image {
    width: 350px;
    margin-left: 70px;
  }

  .stat {
    margin-bottom: 40px;
  }


/* Mover el círculo una vez más */

.circle {
      background-color: transparent;
      border:3px solid purple;
      height:90px;
      position: relative;
      top: -30px;
      left: 150px;
      border-radius:50%;
      -moz-border-radius:50%;
      -webkit-border-radius:50%;
      width:90px;
  }
}</code></pre><p>Y voila!</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2021/09/ezgif.com-gif-maker--4--1.gif" class="kg-image" alt="ezgif.com-gif-maker--4--1" width="600" height="400" loading="lazy"></figure><h2 id="concluyendo"><strong>Concluyendo</strong></h2><p>FlexBox y Grid son herramientas muy poderosas para distribuir el contenido de una página web de la manera que gustes. </p><p>Se puede argumentar que el diseño responsivo es uno de los principios más importantes del desarrollo web. Debemos considerar el hecho de que nuestro sitio será visto desde varios tipos de dispositivos con diferentes resoluciones de pantalla. Optimizar la distribución del contenido de nuestro sitio para diferentes pantallas mejorará la experiencia de usuario.</p><p>En este tutorial hemos diseñado una página de inicio simple usando FlexBox, Grid y varias otras propiedades CSS. Hemos también hecho que la página luzca bien en tablets y pantallas móviles.</p><p>El código completo de este proyecto puede ser descargado de su <a href="https://github.com/KingsleyUbah/Skilllz">repositorio en Github</a>.</p><p>Espero que hayas aprendido algo útil a partir de este tutorial. Si tienes alguna sugerencia puedes contactarme en <a href="https://twitter.com/UbahTheBuilder">Twitter</a>. Tambié puedes visitar mi <a href="https://ubahthebuilder.tech/">blog</a> para ver más publicaciones como esta.</p><p>Gracias por seguir conmigo hasta aquí y nos vemos pronto.</p><p></p><hr><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/size/w100/2021/09/profile-pic--4-.png" class="kg-image" alt="Kingsley Ubah" width="600" height="400" loading="lazy"></figure><p><a href="https://www.freecodecamp.org/news/author/ubahthebuilder/"><strong>Kingsley Ubah</strong></a></p><p>Desarrollador Web. Escritor Tecnológico. Educador. Freelancer. Africano en la Industria Tecnológica. escribo tutoriales acerca del desarrollo web/software. Mi blog personal es - ubahthebuilder.tech. Se amable. Sonrie siempre!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como crear una aplicación web moderna usando WordPress y React ]]>
                </title>
                <description>
                    <![CDATA[ Artículo original escrito por Bret Cameron [https://medium.com/@bretcameron] Artículo originalHow to Create a Modern Web App Using WordPress and React [https://www.freecodecamp.org/news/wordpress-react-how-to-create-a-modern-web-app-using-wordpress-ef6cc6be0cd0/] Traducido y adaptado por Israel Palma [/espanol/news/author/israel/] Combina el poder de un front-end con Reacty el CMS más popular de internet. ¿Quieres las ventajas de una moderna SPA React, pero ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-crear-una-aplicacion-web-moderna-usando-wordpress-y-react/</link>
                <guid isPermaLink="false">61073a23bd9dff09271bedf2</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Palma ]]>
                </dc:creator>
                <pubDate>Tue, 26 Oct 2021 12:00:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/10/1_sKZ0nC0gyc5tiqlVBfu_uQ.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p><strong><strong>Artículo original escrito por </strong></strong><a href="https://medium.com/@bretcameron">Bret Cameron</a><br><strong><strong>Artículo original &nbsp;</strong></strong><a href="https://www.freecodecamp.org/news/wordpress-react-how-to-create-a-modern-web-app-using-wordpress-ef6cc6be0cd0/">How to Create a Modern Web App Using WordPress and React</a><br><strong><strong>Traducido y adaptado por</strong> </strong><a href="https://www.freecodecamp.org/espanol/news/author/israel/">Israel Palma</a></p><h4 id="combina-el-poder-de-un-front-end-con-react-y-el-cms-m-s-popular-de-internet-"><strong><strong>Combin</strong>a el poder de un <strong>front-end</strong> con <strong>React &nbsp;</strong>y el<strong> CMS</strong> más popular de internet.</strong></h4><p>¿Quieres las ventajas de una moderna SPA React, pero un back-end que se sienta familiar? En este artículo, cubriremos cómo configurar el REST API de WordPress, incluyendo los "custom post types" (tipos de post personalizados) y "custom fields" (campos personalizados) así como también te mostramos como traer estos datos desde React.</p><p>Recientemente, he trabajado en un app React para un cliente, y ellos me hicieron esta pregunta: ¿Puedo usar React <strong>con WordPress</strong>?</p><p>Desde finales del 2015 la respuesta a esta pregunta ha sido, si. Pero los pasos necesarios para crear un sitio des-acoplado que trabaje bien podría no parecer tan clara o sencilla, especialmente para quienes no están familiarizados con WordPress y React.</p><p>En mi trayectoria al crear una aplicación (WordPress + React) que funcionara me encontré con un montón de obstáculos engañosos que en este artículo explicaré como evitar. También comparto muchos otros trucos y tips que aprendí en el camino.</p><h3 id="contenido"><strong><strong>Conten</strong>ido</strong></h3><h3 id="parte-1-antecedentes">Parte 1: Antecedentes &nbsp;</h3><ul><li>¿Qué es un Headless CMS?</li><li>¿Que necesito saber?</li><li>Acrónimos clave</li><li>¿Dónde puedo ver los datos JSON de WordPress?</li></ul><h4 id="parte-2-wordpress"><strong><strong>Part</strong>e<strong> 2: WordPress</strong></strong></h4><ul><li>Agregando un Custom Post Type</li><li>Cambiando el texto de relleno del título</li><li>Agregando un "Custom Field" a tu "Custom Post Type"</li><li>Haciendo &nbsp;que los Custom Fields estén disponibles en formato JSON</li><li>Restringiendo la visibilidad de los datos JSON </li></ul><h4 id="parte-3-react"><strong><strong>Part</strong>e<strong> 3: React</strong></strong></h4><ul><li>Promesas en JavaScript</li><li>El método Fetch </li><li>Usando Promesas</li></ul><h4 id="un-ejemplo-que-trabaja-bien"><strong>Un ejemplo que trabaja bien</strong></h4><h4 id="conclusi-n"><strong><strong>Conclusi</strong>ó<strong>n</strong></strong></h4><h3 id="parte-1-antecedentes-1"><strong><strong>Part</strong>e<strong> 1:</strong> Antecedentes<strong> </strong></strong></h3><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*V5SV3AAoVrt9qjiWsTabbg.png" class="kg-image" alt="1*V5SV3AAoVrt9qjiWsTabbg" width="800" height="225" loading="lazy"></figure><h4 id="-qu-es-un-headless-cms"><strong>¿Qué es un<strong> Headless CMS?</strong></strong></h4><p>Antes usar un CMS como WordPress significaba que tenías que crear tu frontend usando PHP.</p><p>Ahora con headless CMS puedes construir tu front-end con cualquier tecnología que prefieras; esto gracias a la separación (des-acoplamiento) entre el front-end y el back-end vía una API. Si quieres crear una SPA (Aplicación de Página Única) usando React, Angular o Vue, y controlar el contenido usando un CMS como WordPress, ya es posible!</p><h4 id="-qu-necesito-saber"><strong>¿Qué necesito saber<strong>?</strong></strong></h4><p>Sacarás el máximo provecho de este artículo si tienes:</p><ul><li>Algún conocimiento de cómo funciona un CMS como WordPress, un poco de PHP, y alguna idea de como configurar un proyecto WordPress en tu computadora.</li><li>Entender JavaScript, incluyendo las características de las versiones ES6+ y la sintaxis de clases en React.</li></ul><h4 id="acr-nimos-clave"><strong><strong>Acr</strong>ó<strong>n</strong>i<strong>m</strong>o<strong>s</strong> clave</strong></h4><p>La programación está llena de jerga, pero esta nos permite platicar de manera más rápida los conceptos en este artículo. Aquí un rápido repaso de los términos que usaremos:</p><ul><li><strong><strong>CMS — </strong>Sistema para el Manejo de Contenido (<strong>content management system</strong>)<strong>.</strong></strong> Piensa en WordPress, Drupal, Joomla, Magento.</li><li><strong><strong>SPA — </strong>Aplicación de Página Única (S<strong>ingle-</strong>P<strong>age </strong>A<strong>pplication</strong>)<strong>.</strong></strong> &nbsp;En lugar de re-cargar cada página por completo, una SPA carga el contenido dinámicamente. El código fundamental del sitio web (HTML, CSS y JavaScript) se carga una sóla vez. Piensa en React, Vue, Angular.</li><li><strong><strong>API —</strong> Interfaz de Programación de Aplicaciones<strong> </strong>(<strong>application programming interface</strong>)<strong>.</strong></strong> En términos sencillos, es una serie de definiciones que un servicio provee para permitirte tomar y utilizar sus datos. Google Maps tiene una, Medium tiene una. Y ahora cada website hecho con WordPress viene con una API incluida.</li><li><strong><strong>REST —</strong><a href="https://es.wikipedia.org/wiki/Transferencia_de_Estado_Representacional"><strong> </strong>Transferencia de Estado Representacional</a> (<strong>representational state transfer</strong>)<strong>.</strong></strong> Un estilo de arquitectura web basado alrededor de los métodos HTTP: <code>GET</code> , <code>PUT</code> , <code>POST</code> y <code>DELETE</code> . El API de WordPress es un API REST o API “RESTful”.</li><li><strong><strong>HTTP —</strong> Protocolo de Transferencia de Hipertexto<strong> </strong>(<strong>hypertext transfer protocol</strong>)<strong>.</strong></strong> El conjunto de reglas utilizadas para transferir datos a través de la web. Se especifica el inicia de URLs como <code>http</code> or <code>https</code> (la versión segura).</li><li><strong><strong>JSON — </strong>Notación de Objetos JavaScript (<strong>JavaScript object notation</strong>)<strong>.</strong></strong> Aunque es un acrónimo derivado de JavaScript, JSON es un formato independiente de lenguajes para almacenar y transmitir datos.</li></ul><p>En este artículo estamos usando WordPress como nuestro CMS. Lo que quiere decir que programaremos nuestro "backend" en PHP y usando la REST API de WordPress para enviar datos JSON al "frontend".</p><h4 id="-d-nde-puedo-ver-los-datos-json-de-wordpress"><strong>¿Dónde puedo ver los datos JSON de <strong>WordPress?</strong></strong></h4><p>Antes de llegar a lo bueno, veamos una rápida nota acerca de en dónde puedes encontrar los datos JSON de tu sitio WordPress. En la actualidad , cada sitio WordPress cuenta con datos JSON a tu disposición (a menos que el propietario del sitio haya deshabilitado o restringido el acceso a estos). Puedes echar un vistazo al JSON principal de un sitio WordPress al agregar &nbsp;<code>/wp-json</code> a la url del dominio principal del sitio.</p><p>Entonces, por ejemplo, puedes dar un vistazo a el JSON de WordPress.org visitando <a href="https://wordpress.org/wp-json" rel="noopener">https://wordpress.org/wp-json</a>. O, si estás corriendo un sitio WordPress de manera local, puedes ver sus datos JSON en la siguiente dirección &nbsp;<code>localhost/yoursitename/wp-json</code>.</p><p>Para tener acceso a los datos de tus publicaciones (posts), escribe &nbsp;<code>localhost/yoursitename/wp-json/wp/v2/posts</code> . Para un formato personalizado (custom post format), intercambia el nuevo formato (ej. <code>movies</code>) en lugar de &nbsp;<code>posts</code>. Lo que ahora se ve como un bloque de texto ilegible nos permitirá usar WordPress como un "headless CMS"! - del inglés Sistema de Manejo de Contenidos sin Cabecera; lo que significa que no incluye la capa de presentación.</p><h3 id="parte-2-wordpress-1"><strong><strong>Part</strong>e<strong> 2: WordPress</strong></strong></h3><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*jUVbqOjhcy-68oCBkIlm2Q.png" class="kg-image" alt="1*jUVbqOjhcy-68oCBkIlm2Q" width="800" height="225" loading="lazy"></figure><p>Para configurar tu API REST, la mayor parte de lo que necesitas sucederá en tu archivo <code>functions.php</code>. Asumiré que ya sabes como configurar un proyecto WordPress y tener acceso a este mediante &nbsp;<code>localhost</code>.</p><p>Para la mayoría de los proyectos vas a querer utilizar un "custom post type", así que comencemos por configurar uno.</p><h3 id="agregando-un-custom-post-type">Agregando un Custom Post Type</h3><p>Digamos que nuestro sitio es acerca de películas y que queremos un "post type" llamado 'movies'. Primero tendremos que asegurarnos que nuestro "post type" 'movies' (películas) se cargue lo antes posible, así que lo adjuntáremos al hook &nbsp;<code>init</code> usando <code>add_action</code> :</p><pre><code>add_action( 'init', 'movies_post_type' );</code></pre><p>Estoy utilizando el nombre de función <code>movies_post_type()</code> , pero puedes llamar la función como tu gustes.</p><p>A continuación vamos a registrar 'movies' como un "post type" con la función <code>register_post_type()</code>.</p><p>El siguiente bloque de código podría parecer demasiado complejo pero es relativamente simple: nuestra función toma muchos argumentos para controlar la funcionalidad de nuestro nuevo "post type" y la mayoría de estos se explican muy bien por sus propios nombres. Pondremos estos argumentos en nuestro arreglo &nbsp;(array) <code>$args</code> .</p><p>Uno de los argumentos es &nbsp;<code>labels</code>, este también puede tomar diferentes argumentos así que lo separaremos en un arreglo aparte, <code>$labels</code> , dándonos:</p><p>Dos de los argumentos más importantes son <code>'supports'</code> y <code>'taxomonies'</code> , lo cual se debe a que estos argumentos controlan cuales de los campos post nativos serán accesibles en nuestro nuevo "post type".</p><p>En el código de arriba optamos por sólo tres &nbsp;<code>'supports'</code>: </p><ul><li><code>'title'</code>— el título de cada post.</li><li><code>'editor'</code>— el editor de texto principal, que usaremos en nuestra descripción.</li><li><code>'thumbnail'</code>— la imagen destacada del post.</li></ul><p>Para ver la lista completa de lo que se encuentra disponible revisa <a href="https://developer.wordpress.org/reference/functions/post_type_supports/">aquí para supports</a> y <a href="https://wordpress.org/support/article/taxonomies/">acá para taxonomías</a>. </p><p>"Generate WordPress" también tiene <a href="https://generatewp.com/post-type/">una práctica herramienta para ayudarte a codificar los "custom post types</a>" mucho más </p><h4 id="cambiando-el-texto-de-relleno-placeholder-del-t-tulo-"><strong>Cambiando el texto de relleno (placeholder) del título.</strong></h4><p>Si el texto de relleno "escribe el título aquí" (en inglés "enter title here") es un poco confuso para tu "custom post type" puedes editarlo en una función distinta.</p><h4 id="agrega-un-campo-personalizado-a-tu-custom-post-type"><strong>Agrega un campo personalizado a tu<strong> </strong>c<strong>ustom </strong>p<strong>ost </strong>t<strong>ype</strong></strong></h4><p>¿Que tal si necesitas un campo que no viene pre-definido en la interface de WordPress? Por ejemplo, digamos que queremos un campo especial llamado "Género". En ese caso, necesitarás usar la función <code>add_meta_boxes()</code> .</p><p>Esto debido a que necesitaremos adjuntar una nueva función al hook (gancho) de WordPress &nbsp;<code>add_meta_boxes</code>: </p><pre><code>add_action( 'add_meta_boxes', 'genre_meta_box' );</code></pre><p>Dentro de nuestra nueva función, necesitamos llamar la función de WordPress &nbsp;<code>add_meta_box()</code> de la siguiente manera: </p><pre><code>function genre_meta_box() {  add_meta_box(    'global-notice',    __( 'Genre', 'sitepoint' ),    'genre_meta_box_callback',    'movies',    'side',    'low'  );}</code></pre><p>Puedes leer más acerca de los argumentos de esta función <a href="https://developer.wordpress.org/reference/functions/add_meta_box/">aquí</a>. Para nuestros propósitos la parte más crítica es la función callback, que hemos llamado &nbsp;<code>genre_meta_box_callback</code> . Esta define los contenidos del meta box. Sólo necesitamos ingresar texto así que podemos usar:</p><pre><code>function genre_meta_box_callback() {  global $post;  $custom = get_post_custom($post-&gt;ID);  $genre = $custom["genre"][0];  ?&gt;  &lt;input style="width:100%" name="genre" value="&lt;?php   echo $genre; ?&gt;" /&gt;  &lt;?php};</code></pre><p>Finalmente, nuestro custom field no guardará el valor que contiene a menos que le digamos que lo haga. Para este propósito podemos definir una nueva función &nbsp;<code>save_genre()</code> y adjuntar a el hook &nbsp;<code>save_post</code> de WordPress:</p><pre><code>function save_genre(){  global $post;  update_post_meta($post-&gt;ID, "printer_category",   $_POST["printer_category"]);};</code></pre><pre><code>add_action( 'save_post', 'save_genre' );</code></pre><p>Ya completo, el código que usamos para crear el "custom field" debería verse algo así:</p><h4 id="haciendo-que-los-custom-fields-est-n-disponibles-en-formato-json"><strong>Haciendo que los custom fields estén disponibles en formato JSON</strong></h4><p>Nuestros "custom posts" están automáticamente disponibles en formato JSON. Para nuestro post type "movies", los datos en formato JSON están disponibles en &nbsp;<code>localhost/yoursitename/wp-json/wp/v2/movies</code> .</p><p>Sin embargo nuestros custom fields no son están incluídos automáticamente, así que necesitamos agregar una función para asegurarnos de que también son accesibles mediante la REST API. &nbsp;</p><p>Primero, necesitaremos adjuntar una nueva función al hook &nbsp;<code>rest_api_init</code> :</p><pre><code>add_action( 'rest_api_init', 'register_genre_as_rest_field' );</code></pre><p>Luego, podremos utilizar la función <code>register_rest_field()</code> así: </p><pre><code>function register_genre_as_rest_field() {  
	register_rest_field(    
    	'movies',    
        'genre',    
        array(      
        'get_callback' =&gt; 'get_genre_meta_field',      
        'update_callback' =&gt; null,      
        'schema' =&gt; null,
        ) 
     );
 }</code></pre><p>Esta función toma un arreglo con los callbacks <code>get</code> y <code>update</code> . Para un caso de uso más simple y claro, podemos sólo especificar un &nbsp;<code>'get_callback'</code> :</p><pre><code>function get_genre_meta_field( $object, $field_name, $value ) {  
	return get_post_meta($object['id'])[$field_name][0];
}</code></pre><p>En términos generales, este es el código necesario para registrar un custom field.</p><h4 id="haciendo-que-las-urls-de-las-im-genes-destacadas-est-n-disponibles-en-formato-json"><strong>Haciendo que las URLs de las imágenes destacadas estén disponibles en formato <strong>JSON</strong></strong></h4><p>La REST API de WordPress no incluye de antemano una URL para tus imágenes destacadas. Para hacerlo más fácil tener acceso puedes usar el siguiente código:</p><p>El filtro de WordPress <code>rest_prepare_posts</code> es dinámico, así que podemos meter nuestro custom post type en el lugar de la palabra "posts", de la siguiente forma: &nbsp;<code>rest_prepare_movies</code> . </p><h4 id="restringiendo-cu-les-datos-json-son-visibles"><strong>Restringiendo cuáles datos JSON son visibles</strong></h4><p>Estamos casi listos para empezar a traer datos a nuestro app React, pero hay una optimización más que podemos hacer, al limitar los datos que están disponibles.</p><p>Algunos datos vienen de manera estándar pero que podrías nunca necesitar en tu frontend y (de ser este el caso) podemos removerlos usando un filtro, como este. Puedes encontrar los nombres &nbsp;de los tipos de datos dándole un vistazo a la URL &nbsp;<code>/wp-json/wp/v2/movies</code> &nbsp;de tu website.</p><p>Con eso terminado, una vez que hayas agregado unas cuántas películas usando el backend de WordPress, tenemos todo lo que necesitamos para empezar a traer los datos a React!</p><h3 id="parte-3-react-1"><strong><strong>Part</strong>e<strong> 3: React</strong></strong></h3><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*qKj1pMwgVFGtOID_wD1N-g.png" class="kg-image" alt="1*qKj1pMwgVFGtOID_wD1N-g" width="800" height="225" loading="lazy"></figure><p>Para obtener datos externos en JavaScript, necesitas usar promesas. Esto probablemente tendrá implicaciones para la manera en que quieres estructurar tus componentes React y en mi caso (convertir un proyecto React existente), tuve que re-escribir una cantidad considerable de código. &nbsp;</p><h4 id="promesas-en-javascript"><strong><strong>Prom</strong>e<strong>s</strong>a<strong>s </strong>e<strong>n JavaScript</strong></strong></h4><p>Las promesas en JavaScript son utilizadas para manejar acciones asíncronas; cosas que suceden fuera del orden de ejecución usual o síncrono. </p><p>La buena noticia es que JavaScript asíncrono es más fácil de lo que solía ser. Antes de ES6, dependíamos de las funciones callback. Si eran necesarias múltiples callbacks (y frecuentemente lo eran), la anidación nos llevaría a escribir código que era muy difícil de leer, escalar y corregir; un fenómeno que se conoce como el "callback hell" (infierno de retro-llamadas) o "pyramid of doom"! (pirámide de la condena). </p><p>Las promesas fueron introducidas en ES6 (ES2015) para resolver el problema del callback hell, y ES8 (ES2018) vio la introducción de <code>async ... await</code> , dos palabras clave que simplificarían aún mas la funcionalidad asíncrona. Pero para nuestros propósitos, el método más crítico basado en promesas es <code>fetch()</code> .</p><h4 id="el-m-todo-fetch"><strong>El método <strong>Fetch</strong></strong></h4><p>Este método ha estado disponible desde la versión 40 de Chrome, y es una alternativa más fácil de usar que <code>XMLHttpRequest()</code> . &nbsp;</p><p><code>fetch()</code> devuelve una promesa y por lo tanto podemos usar el método "then" para procesar el resultado.</p><p>Puedes agregar fetch a un método dentro de tu componente clase en React, de esta manera:</p><pre><code>fetchPostData() {  
     fetch(`http://localhost/yoursitename/wp-json/wp/v2/movies?per_page=100`)  	  
    .then(response =&gt; response.json())  
    .then(myJSON =&gt; {  
     	// Logic goes here
     });
}</code></pre><p>En el código de arriba dos cosas son importantes:</p><ul><li>Primero, estamos llamando una URL con el filtro <code>?per_page=100</code> adjunto al final. Por defecto, WordPress sólo muestra 10 items por página y frecuentemente me encuentro queriendo incrementar ese límite.</li><li>Segundo, antes de procesar nuestros datos, estamos usando el método &nbsp;<code>.json()</code>. Este es utilizado principalmente en relación con <code>fetch()</code>, y devuelve los datos como una promesa además de hacer "parse" al texto de la propiedad body en formato JSON. </li></ul><p>En la mayoría de los casos, vamos a querer correr esta función tan pronto como nuestro componente React haya sido montado (mounted), y esto lo podemos especificar usando el método &nbsp;<code>componentDidMount()</code> :</p><pre><code>componentDidMount() {  this.fetchPostData();}</code></pre><h4 id="manejando-promesas"><strong>Manejando<strong> </strong>p<strong>rom</strong>e<strong>s</strong>a<strong>s</strong></strong></h4><p>Una vez que se a devuelto una promesa, tienes que tener cuidado en manejarla en el contexto adecuado.</p><p>Cuando intenté usar promesas por primera vez, pasé un rato intentando pasar datos a las variables que se encontraban fuera del<a href="https://en.wikipedia.org/wiki/Scope_(computer_science)"> scope</a> (<a href="https://es.wikipedia.org/wiki/%C3%81mbito_(programaci%C3%B3n)">ámbito</a>) de la promesa. Aquí algunas buenas regla a seguir:</p><ul><li>En React la mejor manera de usar promesas es mediante el uso del estado. Puedes utilizar &nbsp;<code>this.setState()</code> para pasar los datos de la promesa al estado de tu componente.</li><li>Lo mejor es procesar, ordenar y re-agrupar tus datos dentro de una serie de métodos &nbsp;<code>then()</code> encadenados al <code>fetch()</code> inicial. Una vez que se complete el proceso, es una buena práctica agregar los datos al estado dentro de tu método &nbsp;<code>then()</code> final. </li><li>Si quieres llamar cualquier función adicional para procesar tu promesa (incluso dentro de <code>render()</code>) es buena práctica prevenir que la función corra hasta que la promesa se haya resuelto. </li><li>Así que, por ejemplo, si pasas tu promesa a &nbsp;<code>this.state.data</code> , puedes incluir un condicional dentro del cuerpo de cualquiera de las funciones que dependen de ella, como te muestro abajo. Esto puede prevenir molesto comportamiento no deseado!</li></ul><pre><code>myPromiseMethod() {  if (this.state.data) {    // process promise here   } else {    // what to do before the fetch is successful  }}</code></pre><h3 id="un-ejemplo-en-react"><strong>Un ejemplo en React</strong></h3><p>Digamos que queremos traer &nbsp;<code>name</code>, <code>description</code>, <code>featured_image</code> y <code>genre</code> del custom post type que definimos en la parte 1.</p><p>En el siguiente ejemplo, tomaremos esos 4 elementos para cada película y los mostraremos (render) en pantalla.</p><p>El siguiente bloque de código podría parecer intimidante, como es frecuente en los tutoriales React. &nbsp;Pero espero que parezca mucho más simple cuando te lo explique más a detalle.</p><h4 id="constructor-props-"><strong><strong>constructor(props)</strong></strong></h4><p>En este método, llamamos <code>super(props)</code>, para definir nuestro estado inicial (un objeto &nbsp;<code>data</code> vacío) y uniremos (bind) tres nuevos métodos: </p><ul><li><code>fetchPostData()</code></li><li><code>renderMovies()</code></li><li><code>populatePageAfterFetch()</code></li></ul><h4 id="componentdidmount-"><strong><strong>componentDidMount()</strong></strong></h4><p>Queremos traer nuestros datos tan pronto como el componente se haya montado, así que llamaremos <code>fetchPostData()</code> aquí.</p><h4 id="fetchpostdata-"><strong><strong>fetchPostData()</strong></strong></h4><p>Traemos el JSON desde nuestro URL, pasando <code>.json()</code> en el primer método <code>.then()</code> .</p><p>En el segundo método &nbsp;<code>.then()</code> extraemos los cuatro valores que queremos para cada película que hemos traído y luego las agregamos al objeto <code>newState</code> .</p><p>Entonces podemos usar <code>this.setState(newState)</code> para agregar esta información a &nbsp; <code>this.state.data</code> .</p><h4 id="rendermovies-"><strong><strong>renderMovies()</strong></strong></h4><p>El condicional &nbsp;<code>if (this.state.data)</code> significa que la función correrá solamente una vez que los datos hayan sido extraídos (fetched).</p><p>Aquí, tomamos un arreglo de todas nuestras películas extraídas de &nbsp;<code>this.state.data</code> &nbsp;y lo pasamos a la función &nbsp;<code>populatePageAfterFetch()</code> .</p><h4 id="populatepageafterfetch-"><strong><strong>populatePageAfterFetch()</strong></strong></h4><p>En esta función preparamos los datos para que cada película sea "renderizada" (mostrada en pantalla). Esto debería ser sencillo para cualquiera que haya utilizado JSX; con un potencial obstáculo.</p><p>El valor de &nbsp;<code>movie.description</code> no es texto simple sino HTML. Para mostrar esto podemos usar &nbsp;<code>dangerouslySetInnerHTML={{__html: movie.description}}</code> .</p><p><strong>Nota:</strong> La razón por la que esto es <em>potencialmente "peligroso"</em> es que si tus datos fueran interceptados y recibieran una inyección de <em><a href="https://es.wikipedia.org/wiki/Cross-site_scripting">scripts XSS</a>, </em>este podría ser también &nbsp;consumido y a su vez interpretado por el navegador de los usuarios. Como estamos usando nuestro propio servidor/CMS en este artículo, no deberíamos preocuparnos. Pero si quieres sanear (sanitize) tu HTML, dale un vistazo a <em><em> <a href="https://github.com/cure53/DOMPurify" rel="noopener">DOMPurify</a>.</em></em> &nbsp;</p><h4 id="render-"><strong><strong>render()</strong></strong></h4><p>Finalmente, controlaremos donde aparecerán nuestros datos renderizados al llamar el método <code>renderMovies()</code> dentro de las etiquetas HTML <code>&lt;div&gt;</code> seleccionadas. Ahora hemos extraído datos desde nuestro sitio WordPress exitosamente y los hemos mostrado en pantalla! </p><h3 id="conclusi-n-1"><strong><strong>Conclusi</strong>ó<strong>n</strong></strong></h3><p>Espero que este artículo haga que el proceso de conectar un front-end React con Wordpress sea tan sencillo y libre de frustraciones como sea posible. </p><p>Como muchas cosas en la programación, lo que puede lucir intimidante pronto empezará a sentirse como instinto natural!</p><p>Estoy muy interesado en conocer tus propias experiencias usando WordPress como un CMS headless y estaría feliz de responder cualquiera de tus preguntas en los comentarios.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Como automatizar el despliegue en GitHub-pages con Travis CI ]]>
                </title>
                <description>
                    <![CDATA[ > Aviso: Este artículo no es patrocinado por ninguna de las tecnologías (compañías) que se describen aquí (Travis-CI, Github, Github-Pages) Digamos que has creado un proyecto con React.js y lo desplegaste en GitHub-pages (aún no?? —crea tu primer proyecto con React.js [https://medium.com/free-code-camp/portfolio-app-using-react-618814e35843]  -artículo en inglés). Pero qué tal si realizas ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-automatizar-el-despliegue-en-github-pages-con-travis-cl/</link>
                <guid isPermaLink="false">601de8e762984e09f608596c</guid>
                
                    <category>
                        <![CDATA[ DevOps ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Palma ]]>
                </dc:creator>
                <pubDate>Mon, 12 Apr 2021 05:13:00 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/02/Druhv-article-image.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <blockquote>Aviso: Este artículo no es patrocinado por ninguna de las tecnologías (compañías) que se describen aquí (Travis-CI, Github, Github-Pages)</blockquote><p>Digamos que has creado un proyecto con React.js y lo desplegaste en GitHub-pages (aún no?? — <a href="https://medium.com/free-code-camp/portfolio-app-using-react-618814e35843">crea tu primer proyecto con React.js</a> -artículo en inglés). Pero qué tal si realizas cambios frecuentes al código y además quieres que la versión desplegada (producción) se encuentre siempre actualizada? ... ¡Te encontrarás con un tedioso proceso que consiste en correr scripts para el despliegue una y otra vez!!!</p><blockquote>Qué tal si el proceso pudiera ser automatizado??</blockquote><p>Luego de una sesión rápida de búsqueda en google, encontré que es posible y puede ser logrado usando Travis CI—una herramienta de código abierto para automatizar el despliegue de varios tipos de proyectos.</p><h2 id="lo-que-aprender-s"><strong>Lo que aprenderás<strong> &gt;</strong></strong></h2><p>En este artículo vas a aprender como implementar el sistema que disparará los scripts para despliegue de React usando TRAVIS-CI, para así lograr desplegar el proyecto a GitHub-pages, cuando sea que haya cambios por desplegar en la rama principal (master branch) del repositorio.</p><ul><li>A configurar el despliegue automatizado del proyecto <strong><strong>‘</strong></strong><a href="https://medium.com/free-code-camp/portfolio-app-using-react-618814e35843"><strong><strong>react-portfolio’</strong></strong></a> </li><li>Aprender acerca de algunos errores frecuentemente encontrados en este proceso.</li><li>Aprenderás algunos conceptos relacionados al ‘<strong><strong>continuous deployment’</strong></strong> (despliegue continuo).</li></ul><h2 id="aprendamos-algunos-fundamentos"><strong>Aprendamos algunos fundamentos</strong></h2><blockquote>Brinca esta sección sino eres del tipo (fundamentos primero)!!</blockquote><h3 id="continuous-integration-ci-continuous-delivery-cd-"><strong><strong>Continuous Integration(CI) &amp; Continuous Delivery(CD) &gt;</strong></strong></h3><p>-Integración Continua (IC) y Entrega Continua (EC)</p><blockquote>“En <a href="https://es.wikipedia.org/wiki/Ingenier%C3%ADa_de_software">ingeniería de software </a>, la Integración Continua (CI) es la práctica de integrar todos las copias funcionales de los desarrolladores en una rama central (shared <a href="https://en.wikipedia.org/wiki/Trunk_%28software%29" rel="noopener">mainline</a> /trunk) varias veces al día” — <a href="https://es.wikipedia.org/wiki/Integraci%C3%B3n_continua">wikipedia</a></blockquote><p>Dicho de otra forma, los desarrolladores tratarán de fusionar (merge) sus cambios o características nuevas en la rama master tan frecuentemente como sea posible. Seguir esta práctica permite que los desarrolladores y gerentes de producto realicen el lanzamiento del producto más frecuentemente.</p><p>Existen algunas versiones extendidas de CI pipelines (canales CI) donde estos cambios también pueden ser puestos a prueba (testing) automáticamente, lo que hace que el código sea desplegable en todo momento; esto se conoce como <strong><strong>‘Continuous Delivery</strong></strong>’ (entrega continua). Una extensión aún mayor a este canal o pipeline se conoce como <strong><strong>‘Continuous Deployment’</strong> </strong>(Despliegue continuo), donde estos cambios ya puestos a prueba (tested) son subidos automáticamente a los servidores de producción. (Estaremos implementando el pipeline de despliegue continuo en nuestro caso).</p><h3 id="travis-ci"><strong><strong>Travis CI &gt;</strong></strong></h3><p><strong><strong>Travis CI </strong></strong>es un servicio alojado de integración continua (CI) utilizado para desarrollar y probar (test) proyectos de software alojados en GitHub. ¡Con el que se pueden realizar pruebas a proyectos de código abierto sin cargos!!</p><p>Travis CI puede ser configurado agregando el archivo <code>.travis.yml</code> al repositorio. Cuando Travis CI ha sido activado para un repositorio, GitHub notificará cuando sea que nuevos commits sean realizados en el repositorio o cualquier pull request sea enviado que cumpla con las reglas definidas en el archivo <code>.travis.yml</code>, Travis CI ejecutará los pasos necesarios, que pueden ser— desde correr pruebas, hacer un build de la aplicación o ejecutar scripts para despliegue. Travis CI ofrece una amplia gama de opciones y lenguajes para desarrollar software y claro, nuestro amado <code>javascript</code> es una de esas opciones.</p><blockquote><strong><strong>NOT</strong>A</strong><em><em><strong><strong>: </strong></strong>Git</em>H<em>ub</em> tiene un<em> &nbsp;</em></em><a href="https://education.github.com/pack">pack para desarrolladores estudiantes</a><em><strong> </strong><em> </em>disponible con un montón de características premium gratuitas para estudiantes, que incluye varias plataformas <em> (Travis CI </em>es una de ellas<em>)</em> <em>— </em> obtén tu <a href="https://education.github.com/pack">"student pack"</a> ahora<em>!!</em></em></blockquote><h3 id="devops"><strong><strong>DevOps &gt;</strong></strong></h3><p><strong><strong>DevOps</strong></strong> es un grupo de prácticas que combinan el <a href="https://es.wikipedia.org/wiki/Proceso_para_el_desarrollo_de_software">desarrollo de software</a> (Dev) y &nbsp;<a href="https://en.wikipedia.org/wiki/Information_technology_operations">operaciones de tecnologías informáticas</a> (Ops) para acortar los <a href="https://es.wikipedia.org/wiki/Systems_Development_Life_Cycle">ciclos de vida en el desarrollo de sistemas</a> mientras se entregan características, corrección de errores y actualizaciones de manera continua y frecuente. El concepto DevOps se fundamenta en la construcción de una cultura de colaboración entre equipos.</p><blockquote>“DevOps es más que una práctica  — se trata de una cultura”</blockquote><p>Integración continua, entrega continua, despliegue continuo; son algunas de las prácticas clave del DevOps. Además los ingenieros DevOps aprovechan fuertemente el poder de la infraestructura de la nube para hacer el proceso de despliegue impecable.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*9pVLG4BzEWIcMnfhFp9ULQ.png" class="kg-image" alt="1*9pVLG4BzEWIcMnfhFp9ULQ" width="1600" height="823" loading="lazy"></figure><hr><h2 id="-paremos-de-hablar-pongamos-manos-a-la-obra-"><strong>¡Paremos de hablar<strong>!!! </strong>Pongamos manos a la obra.</strong></h2><p>Como ya has desplegado en GitHub pages usando el módulo node <code>gh-pages</code>, habrá una rama llamada <code>gh-pages</code> en el repositorio, que contiene los archivos que son desplegados a los servidores de GitHub pages. Luego de la integración de Travis CI, seremos capaces de implementar el sistema que desatará un "build" (compilación/transpilación del código) automáticamente cada vez que el usuario realice cambios a la rama <code>master</code>. Si el "build" es exitoso, los "build scripts" serán disparados, lo que actualizará la rama <code>gh-pages</code>. Travis CI notificará entonces al usuario acerca del estatus del build via correo electrónico.</p><p></p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*athThq_0-5cg1foDqt0v5w.png" class="kg-image" alt="1*athThq_0-5cg1foDqt0v5w" width="1052" height="744" loading="lazy"></figure><h3 id="crea-una-cuenta-en-travis-ci"><strong><strong>Crea </strong>u<strong>n</strong>a<strong> </strong>cuenta en<strong> Travis-CI &gt;</strong></strong></h3><ul><li>Ve a <a href="https://travis-ci.com/" rel="noopener">Travis-ci.com</a> y r<em><a href="https://travis-ci.com/signin">egístrate con<em> GitHub</em></a></em>.</li><li>Acepta los términos y condiciones de Travis CI. Serás redireccionado a GitHub.</li><li>Da clic al botón de activar (Activate), selecciona los repositorios que desea utilizar con Travis CI.</li><li>Se agregará automáticamente un token de autorización cuando inicies sesión en GitHub.</li></ul><h3 id="agrega-el-archivo-travis-yml-al-repositorio"><strong>Agrega el archivo<strong> travis.yml </strong>al<strong> repositor</strong>io<strong> &gt;</strong></strong></h3><p>Este archivo contiene las instrucciones que instruyen a Travis-CI — qué?..cómo?..cuándo?</p><blockquote><strong><strong>NOT</strong>A</strong>: Cuando dispares una tarea en Travis-CI, este iniciará una máquina virtual con el entorno de despliegue apropiado según la configuración en el archivo <em><em><code>.travis.yml</code></em></em></blockquote><p>Revisemos el código paso a paso —</p><figure class="kg-card kg-code-card"><pre><code class="language-yml">language: node_js
node_js:
  - "stable"
cache:
  directories:
  - node_modules
script:
  - npm run build
deploy:
  provider: pages
  skip_cleanup: true
  github_token: $github_token
  local_dir: build
  on:
    branch: master</code></pre><figcaption>archivo .travis.yml</figcaption></figure><p><code>on</code> : Travis-CI disparará automáticamente una tarea en cuanto haya cambios en la rama especificada en este campo.</p><p><code>deploy</code> : En este campo hemos declarado que usaremos el <a href="https://docs.travis-ci.com/user/deployment/pages/">proveedor de despliegue para GitHub pages</a> &nbsp;que nos brinda Travis-CI, que no es otra cosa que las instrucciones de configuración para preparar el entorno para realizar el despliegue. </p><p><code>script</code> : Contiene los "build scripts" (código para "construir", compilar o transpilar el proyecto) que serán ejecutados mientras se corre la tarea. Para este caso puedes agregar "test scripts" (para pruebas; <a href="https://es.wikipedia.org/wiki/Cobertura_de_c%C3%B3digo">cobertura de código</a>, pruebas de fusión, etc. ) antes del "build". </p><p><code>cache</code> : Travis-CI nos permite guardar en caché los archivos de librerías y módulos para cada "build". Los archivos en la caché pueden ser reutilizados para los próximos builds, de esta forma podemos reducir el tiempo de ejecución de extremo a extremo en cada ejecución. </p><h2 id="todo-listo"><strong>Todo listo<strong> &gt;</strong></strong></h2><p>Muy bien ahora todo está en su lugar, de ahora en adelante si confirmas ( <code>commit</code> ) algún cambio en la rama <code>master</code> se desatará una rutina (build) de Travis-CI que se verá más o menos como en las capturas de pantalla de abajo. También puedes disparar un build manualmente desde el panel de control de Travis-CI.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/1*W34g38dx2jy5wxP4yS5y3w.png" class="kg-image" alt="1*W34g38dx2jy5wxP4yS5y3w" width="1600" height="649" loading="lazy"><figcaption>Rutina Travis-CI (ejecutándose)</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/1*V6MOHQiV2agPnAtfo6Wyjw.png" class="kg-image" alt="1*V6MOHQiV2agPnAtfo6Wyjw" width="1600" height="558" loading="lazy"><figcaption>Rutina Travis-CI (exitosa)</figcaption></figure><h2 id="pero-siempre-hay-un-pero-eh-"><strong>Pero<strong> …. (</strong>siempre hay un pero<strong>!! </strong>e<strong>h</strong>?<strong>!)</strong></strong></h2><p>Estoy seguro de que tu panel de control no se verá como el de arriba tan fácilmente, tal como en la vida las cosas no siempre salen como uno espera. Puede haber infinitas razones por las cuales tu panel de control en Travis-CI se llene de builds fallidos (lo sé porque ya me ha pasado).</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*xoGfeAu4sb-_l7ggTbjC7Q.png" class="kg-image" alt="1*xoGfeAu4sb-_l7ggTbjC7Q" width="1600" height="591" loading="lazy"></figure><p>Este es el momento cuando tus más valiosas habilidades para "googlear" van a ser muy útiles. Explicaré todos los errores que he encontrado al intentar crear un canal o "pipeline".</p><ul><li>Errores de seguridad</li><li>Errores con el token </li><li>Errores de tipo aleatorio (Necesitarás ensuciarte las manos para encontrar la solución!!)</li></ul><h3 id="errores-con-los-tokens"><strong>E<strong>rror</strong>e<strong>s </strong>con los t<strong>oken</strong>s<strong> &gt;</strong></strong></h3><p>Si tus builds fallan debido a errores con los permisos entonces hay muchas probabilidades de que tenga que ver con <a href="https://github.com/settings/tokens">problemas con los tokens</a>. Necesitas ir al URL <a href="https://github.com/settings/tokens" rel="noopener">https://github.com/settings/tokens</a> y ver cuando fue la última vez que se usaron, si muestra que no han sido usados <strong>nunca, </strong>habrás encontrado al culpable.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*9NrQnLn0Mrp7Oex9H_F-Og.png" class="kg-image" alt="1*9NrQnLn0Mrp7Oex9H_F-Og" width="1600" height="479" loading="lazy"></figure><p>Para arreglarlo sigue estos pasos,</p><ul><li>Borra el token y crea uno nuevo</li><li>Agrega el token a las variables de entorno de Travis (en las configuraciones de rutina/job)</li><li>Reintenta el build</li></ul><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/1*5CtnigPrV0L3ylole9kvVw.png" class="kg-image" alt="1*5CtnigPrV0L3ylole9kvVw" width="1600" height="966" loading="lazy"></figure><h3 id="errores-de-seguridad"><strong>Errores de seguridad<strong> &gt;</strong></strong></h3><p>Hay muchas prácticas de seguridad que ignoramos al programar y crear aplicaciones. Cuando corremos nuestro proyecto localmente no les damos mucha importancia y frecuentemente los descartamos como simples advertencias, pero cuando tratamos de desplegar el servicio usando Travis-CI estas advertencias causarán que el build falle.</p><p>Hablaré de los errores que encontré mientras trabajaba en mi proyecto (y te invito a hacer lo mismo con tus errores). Lo genial es que la mayoría de estos errores tienen sus propias páginas dedicadas que explican las causas del problema y ofrecen soluciones o remedios alternativos (Remedios— nos encantan los remedios aunque sepamos que no deberíamos).</p><ul><li><strong>Usar<strong> target=_blank in HTML &lt;href&gt; tag: </strong></strong>Esta vulnerabilidad es más seria de lo que aparenta. Conoce más <a href="https://mathiasbynens.github.io/rel-noopener/" rel="noopener">aquí.</a></li><li><strong>Redundancia en el código<strong> HTML</strong></strong>: Hay muchas etiquetas HTML y nombres de clases redundantes, lo cual hacía que mi código luciera como un desastre. </li></ul><p>La mejor manera de prevenir estos errores es instalar el plug-in <code>es-lint</code> para el editor de texto que uses.</p><hr><h2 id="-creaste-alg-n-proyecto-comp-rtelo-">¿Creaste algún proyecto?<strong> — </strong>Compártelo!</h2><p>Estoy tratando de construir una comunidad de desarrolladores donde la gente puede compartir sus ideas, conocimientos, trabajar con otros y encontrar otras personas con ideologías similares para construir cosas juntos. Así que si construiste algún proyecto y quieres compartirlo, publícalo en el canal.</p><ul><li>Canal en Gitter : <a href="https://gitter.im/weekend-devs/community" rel="nofollow noopener noopener noopener noopener">https://gitter.im/weekend-devs/community</a></li><li>Organización Github : <a href="https://github.com/weekend-developers" rel="nofollow noopener noopener noopener noopener">https://github.com/weekend-developers</a></li></ul><hr><h2 id="para-cerrar"><strong>Para cerrar</strong></h2><p>Me gustaría tomar un momento para reconocer el trabajo de la gente que me ha inspirado y enseñado lo que sé, lo que puedo hacer y así poder escribir este artículo.</p><ul><li><strong>Comunidad <strong>Travis CI :</strong></strong> por proveer herramientas increíbles de forma libre &nbsp;gratuita.</li><li><strong><strong><em><em>M</em></em></strong><em>is mejores amigos</em><strong><em><em>:</em></em></strong></strong> quienes me ayudaron a corregir mis errores.</li><li><strong>TÚ<strong>:</strong></strong> por leer hasta aquí abajo, espero que haya sido una lectura productiva. ¡Continúa explorando y construyendo cosas increíbles!</li></ul><hr><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/0*vNXcdsgZAeulGy1r" class="kg-image" alt="0*vNXcdsgZAeulGy1r" width="1600" height="1066" loading="lazy"><figcaption>Photo by <a href="https://unsplash.com/@clemensvanlay?utm_source=medium&amp;utm_medium=referral" data-href="https://unsplash.com/@clemensvanlay?utm_source=medium&amp;utm_medium=referral" class="markup--anchor markup--figure-anchor" rel="photo-creator noopener noopener noopener" target="_blank" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 17.6px; vertical-align: baseline; background-color: transparent; color: var(--gray90); text-decoration: underline; cursor: pointer; word-break: break-word;">Clemens van Lay</a> on&nbsp;<a href="https://unsplash.com/?utm_source=medium&amp;utm_medium=referral" data-href="https://unsplash.com?utm_source=medium&amp;utm_medium=referral" class="markup--anchor markup--figure-anchor" rel="photo-source noopener noopener noopener" target="_blank" style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: inherit; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 17.6px; vertical-align: baseline; background-color: transparent; color: var(--gray90); text-decoration: underline; cursor: pointer; word-break: break-word;">Unsplash</a></figcaption></figure><p>Traducido del artículo de <strong><a href="https://www.freecodecamp.org/news/author/dhruvbarochiya/">Dhruv Barochiya</a></strong> - <strong><a href="https://www.freecodecamp.org/news/learn-how-to-automate-deployment-on-github-pages-with-travis-ci/">How to automate deployment on GitHub-pages with Travis CI</a></strong></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Git 101: Un flujo de trabajo de Git para que empieces a "subir" (push) código ]]>
                </title>
                <description>
                    <![CDATA[ Explicaré Git de la manera en que habría deseado que alguien lo hiciera cuando yo empecé a aprender a programar. Te mostraré como puedes iniciar con solo unos pocos comandos y los conceptos que hay detrás de estos. Conceptos básicos  Tu código local Este es el resultado del trabajo ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/git-101-un-flujo-de-trabajo-de-git/</link>
                <guid isPermaLink="false">5feac3d68c7cd154bb98144c</guid>
                
                    <category>
                        <![CDATA[ Git ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Palma ]]>
                </dc:creator>
                <pubDate>Mon, 29 Mar 2021 05:10:46 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/04/photo-1556075798-4825dfaaf498.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Explicaré Git de la manera en que habría deseado que alguien lo hiciera cuando yo empecé a aprender a programar.</p><p>Te mostraré como puedes iniciar con solo unos pocos comandos y los conceptos que hay detrás de estos.</p><h2 id="conceptos-b-sicos"><strong>C<strong>oncept</strong>os bá<strong>sic</strong>os<strong> </strong></strong></h2><h4 id="tu-c-digo-local"><strong>Tu código local</strong></h4><p>Este es el resultado del trabajo que haces en tu computadora. Cualquier edición, formato, características o trabajo de desarrollo que tienes en tu computadora es tu código local.</p><h4 id="status-preparado-staged-"><strong>Status "preparado" (s<strong>taged</strong>)</strong></h4><p>Una vez que te sientas satisfecho con los cambios o la cantidad de trabajo realizado, puedes marcar tu código como "preparado". Lo que quiere decir que estás declarando que dichas líneas de código están listas para ser confirmadas (committed).</p><h4 id="el-servidor"><strong>El<strong> serv</strong>ido<strong>r</strong></strong></h4><p>Ya que sientas que los archivos que tienes "preparados" están listos, puedes enviarlos a tu servidor, (GitHub, GitLab, etc.) el cual guarda todo tu código para que otras personas lo puedan ver también (en los casos apropiados). Ahora tus archivos pueden ser vistos por otras personas y ellas pueden trabajar en estos.</p><h3 id="el-objetivo-final">El objetivo final</h3><p>La idea detrás de git es que tu código (digamos de un proyecto) que se encuentra en un servidor remoto debería estar sincronizado con el código que tienes en tu ordenador. Cuando trabajas con otras personas, su código debería estar sincronizado con tu código. Así si tus compañeros o colaboradores "envían" &nbsp;código nuevo, tú también deberías fácilmente poder actualizar tu código para reflejar los cambios que ellos hicieron.</p><p>La meta u objetivo final es que todo lo que se encuentra en el servidor debe ser lo mismo en todas partes, debe ser igual, el mismo código que se encuentra en tu máquina local. Deberías enviar archivos al servidor lo antes posible para que cuando otros vean tus cambios, ellos puedan tener la versión más actual.</p><h3 id="flujo-de-trabajo">Flujo de trabajo</h3><p>Digamos que tienes una carpeta en tu computadora donde se encuentra tu código y quieres ponerlo en GitHub para poder usar control de versiones.</p><p>Aquí te muestro como hacerlo:</p><h3 id="1-creando-un-repositorio-"><strong><strong>1. </strong>Creando un repositorio<strong>.</strong></strong></h3><p>Hay dos maneras de obtener un repositorio - puedes crear uno tu mismo o puedes trabajar con el repositorio de alguien más y contribuir a este. La opción que elijas depende del proyecto en que estés trabajando. Si trabajas en un proyecto propio es más probable que quieras crear un repositorio y empezar a escribir código. Cuando trabajas en código abierto (open source) o en un equipo lo más probable es que vayas a usar un repositorio que ya existe. Hablemos de como hacer ambas. </p><h4 id="crea-un-repositorio"><strong><strong>Crea </strong>un<strong> Repositor</strong>io</strong></h4><p>Primero necesitarás crear una cuenta en <a href="https://github.com/" rel="noopener">GitHub</a> si es que no tienes una aún. Haz clic en la pestaña Repositorios y en "Nuevo" ("New").</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2019/08/image-77.png" class="kg-image" alt="image-77" width="600" height="400" loading="lazy"><figcaption>New button to create new repository</figcaption></figure><p>Sigue las instrucciones para crear tu nuevo repositorio. Digamos que llamamos este repositorio <code>test-repo</code> . Una vez que lo hayas creado, GitHub te muestra como configurarlo en tu computadora de manera local.</p><p>Sigue las instrucciones para crear un nuevo repositorio en la línea de comandos -</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2019/08/image-78.png" class="kg-image" alt="image-78" width="600" height="400" loading="lazy"></figure><h4 id="clonando-un-repositorio"><strong><strong>Clon</strong>ando<strong> </strong>un<strong> repositor</strong>io</strong></h4><p><code>git clone &lt;repositorio&gt;</code></p><p>Digamos que quieres obtener el código en el que yo estoy trabajando para que puedas también trabajar con él en tu computadora. Necesitarás encontrar mi cuenta de GitHub y clonar el repositorio en el que estés interesado. Hoy vamos a trabajar en este repositorio.</p><pre><code>git clone git@github.com:shrutikapoor08/devjoke.git</code></pre><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2019/08/image-85.png" class="kg-image" alt="image-85" width="600" height="400" loading="lazy"></figure><h3 id="2-crea-una-rama-branch-"><br><strong><strong>2. Crea</strong> una rama (branch)</strong></h3><p>Creando una rama ayuda a mantener el trabajo en progreso separado del código que trabaja bien. También ayuda a modular tu código y mantener características separadas mientras aún trabajas en ellas. Hagamos una rama nueva &nbsp;<code>rama-para-chiste</code> usando:</p><p><code>git checkout -b rama-para-chiste</code></p><p>Puedes enviar esta rama al servidor &nbsp;(<code>origin</code>) con  el comando—</p><p><code>git push origin rama-para-chiste</code></p><p>Ahora supongamos que tú y yo somos compañeros de trabajo y estamos trabajando en un proyecto. Repasemos como sería este flujo de trabajo.</p><h3 id="3-modificando-el-c-digo"><strong><strong>3. Modif</strong>icando el código</strong></h3><p>Una vez que comprendas lo que hace el código, estarás listo para hacer ediciones. Si estás trabajando en el repositorio de alguien más, es una buena idea hacer una copia o bifurcación (<code>fork</code>) del repositorio "Forking" es copiar. Es como pasar el repositorio por una copiadora y obtener tu propia copia. Puedes hacer los cambios que quieras o que se necesiten con tu propia copia, editar archivos, borrarlos o agregar nuevos. Si quieres, puedes enviar tus actualizaciones y solicitar que tu código se integre al repositorio original.</p><p>Vamos a crear un fork o copia de este repositorio para modificar el código. Para esto haz clic en el botón "Fork" en la parte superior del repositorio (GitHub).</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2019/08/image-86.png" class="kg-image" alt="image-86" width="600" height="400" loading="lazy"></figure><p>Ahora si vas a tu perfil de GitHub, podrás ver tu recién creado fork del repositorio. ¡Ajá, ajá!</p><p>A continuación vamos a realizar algunos cambios. Abre el archivo <code>README.md</code>. A este archivo vamos a agregar una #DevJoke! (chiste o humor de/para desarrolladores). Pensemos en un chiste bueno y agreguémoslo al inicio de este archivo. Aquí una #DevJoke para ti—</p><blockquote>¿Porqué el programador perdió su trabajo?<br>.<br>.<br>.<br>.<br>¡Por no conseguir un arreglo!</blockquote><h3 id="4-confirmado-los-cambios-"><strong><strong>4. </strong>Confirmado los cambios.</strong></h3><p>Ahora guardemos el archivo y confirmemos &nbsp;los cambios( <code>commit</code> ). Si vas a hacer commit a un archivo recién creado, primero tendrás que agregarlo al área de preparación o "staging". Lo puedes hacer con—</p><p><code>git add &lt;nombre_archivo&gt;</code></p><p>Ya que tu archivo se encuentra "staged", puedes hacer "commit" para confirmar los cambios, asegúrate de agregar un mensaje a tu commit para ayudarte a recordar que cambios realizaste en este commit.</p><p><code>git commit -m "Agregué una #DevJoke"</code></p><h3 id="5-subir-tus-cambios"><strong><strong>5. </strong>Subir tus cambios</strong></h3><p>Recuerda, cuando trabajas en un repositorio en el que otras personas colaboran, es posible que mientras tú modificas tu versión local, ellos podrían haber subido cambios o código nuevo. Así que ahora el servidor va un "paso adelante" de ti. Por lo que necesitas sincronizar tu computadora con el servidor para asegurarte que tienes el código más actual, para ello puedes bajar los últimos cambios del servidor con—</p><p><code>git pull origin &lt;nombre-de-la-rama&gt;</code></p><p>Si nunca has creado una rama, no te preocupes. Git the da la rama &nbsp;<code>master</code> por defecto. También puedes crear una nueva rama con—</p><pre><code>git checkout -b &lt;nueva-rama&gt;</code></pre><p>Ahora que has confirmado los cambios y tu máquina se ha sincronizado con el servidor, estás listo para subir tus modificaciones para que el mundo las vea. Para subir a la rama &nbsp;<code>master</code> , puedes hacerlo con — <code>git push origin master</code>.</p><p>AJÚA!!! Has subido tus primeros cambios usando <code>push</code>! Date una palmadita en la espalda. Esa fue la parte más difícil. Ahora estás listo para confirmar todos los cambios que quieras.</p><h3 id="6-realizando-un-pull-request"><strong><strong>6. </strong>Realizando un<strong> Pull Request</strong></strong></h3><p>Ahora, envíame ese maravilloso chiste (#DevJoke) creando un pull request. Un pull request es una característica por medio de la cual el desarrollador, me solicita —a mí el propietario— fusionar sus cambios con mi repositorio. Crear un pull request es fácil. Ve a github.com y abre el repositorio en el que has estado trabajando.</p><p>Verás un botón para crear un Pull request como este:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2019/08/image-87.png" class="kg-image" alt="image-87" width="600" height="400" loading="lazy"></figure><p>Haz clic en el botón y sigue las instrucciones. Asegúrate que tus cambios se vean correctamente reflejados en la pantalla de "Comparing changes" (comparando cambios).</p><p>¡Haz clic en "Create pull request" (crear pull request) y es todo! ¡Ya acabamos! Has creado tu primer Pull request!</p><p>Ahora envíame ese chiste (#DevJoke)</p><p>Traducido del artículo de <strong><a href="https://www.freecodecamp.org/news/author/shrutikapoor08/">Shruti Kapoor</a></strong> - <a href="https://www.freecodecamp.org/news/git-101-git-workflow-to-get-you-started-pushing-code/">git 101 a git workflow to get you started pushing code</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ La guía definitiva para SSH: Configurando claves SSH ]]>
                </title>
                <description>
                    <![CDATA[ Bienvenido a nuestra guía definitiva para configurar claves SSH (Secure Shell). Este tutorial te llevará a través de los puntos básicos para crear claves SSH y cómo administrar múltiples claves y pares-claves. Crea un nuevo par claves SSH Abre una terminal y ejecuta el siguiente comando: ssh-keygen Verás el siguiente ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/la-guia-definitiva-para-ssh-configuracion-de-claves-ssh/</link>
                <guid isPermaLink="false">5ffe1f7d8c7cd154bb9869b4</guid>
                
                    <category>
                        <![CDATA[ SSH ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ Israel Palma ]]>
                </dc:creator>
                <pubDate>Sat, 20 Mar 2021 05:56:51 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2021/03/photo-1453134765485-7f9a71a803d5-1-.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p>Bienvenido a nuestra guía definitiva para configurar claves SSH (Secure Shell). Este tutorial te llevará a través de los puntos básicos para crear claves SSH y cómo administrar múltiples claves y pares-claves.</p><h2 id="crea-un-nuevo-par-claves-ssh"><strong>Crea un nuevo par claves SSH</strong></h2><p>Abre una terminal y ejecuta el siguiente comando:</p><pre><code class="language-text">ssh-keygen</code></pre><p>Verás el siguiente texto:</p><pre><code class="language-text">// Generando clave par rsa pública/privada.
// Ingresa el archivo en cual guardar la clave (/home/nombre_usuario/.ssh/id_rsa):

Generating public/private rsa key pair.
Enter file in which to save the key (/home/username/.ssh/id_rsa):</code></pre><p>Presiona enter para guardar tus claves al directorio por defecto <code>/home/nombre_usuario/.ssh</code></p><p>Entonces se te requerirá que escribas tu contraseña:</p><pre><code class="language-text">// Ingresa una contraseña (vacío para guardar sin contraseña):
Enter passphrase (empty for no passphrase):</code></pre><p>Es recomendable introducir una contraseña para contar con una capa extra de seguridad. Al configurar una contraseña puedes prevenir el acceso no autorizado a tus servidores y cuentas; en el caso que alguien llegara a tener acceso a tu clave privada SSH o a tu computadora.</p><p>Luego de introducir y confirmar tu contraseña, verás lo siguiente:</p><pre><code class="language-text">// Tu identificación ha sido guardada en /home/nombre_usuario/.ssh/id_rsa.
// Tu clave pública ha sido guardada en /home/username/.ssh/id_rsa.pub.
// La huella digital (fingerprint) de tu clave es:
// SHA256:/qRoWhRcIBTw0D4KpTUyK6YepyL6RQ2CQrtWsaicCb4 username@871e129f767b
// La imagen randomart (arte aleatorio) de tu clave es:

Your identification has been saved in /home/username/.ssh/id_rsa.
Your public key has been saved in /home/username/.ssh/id_rsa.pub.
The key fingerprint is:
SHA256:/qRoWhRcIBTw0D4KpTUyK6YepyL6RQ2CQrtWsaicCb4 username@871e129f767b
The key's randomart image is:
+---[RSA 2048]----+
| .o=+....        |
|+.*o+o .         |
|+X.=o o          |
|@.=.oo .         |
|=O ...o S        |
|o.oo . .         |
|.E+ . . . .      |
|oo . ... +       |
|=.. .o. . .      |
+----[SHA256]-----+</code></pre><p>Ahora ya tienes un par de claves (privada y pública) que puedes usar para tener acceso a servidores remotos de manera segura y manejar la autenticación de programas de línea de comandos como Git.</p><h2 id="administra-m-ltiples-claves-ssh"><strong>Administra múltiples claves SSH</strong></h2><p>Aunque es considerado buena práctica tener un sólo par de claves pública-privada por dispositivo, a veces necesitas usar múltiples claves o tienes nombres para claves no-ortodoxos. Por ejemplo, podrías estar usando un par de claves SSH para trabajar en los proyectos internos de tu compañía, pero podrías estar usando una clave distinta para tener acceso a los servidores de un cliente. Además, podrías estar utilizando una clave diferente para tener acceso a tu propio servidor privado.</p><p>Administrar claves SSH puede tornarse difícil e incómodo tan pronto como necesites utilizar una segunda clave. Tradicionalmente, usarías &nbsp;<code>ssh-add</code> para guardar tus claves en &nbsp;<code>ssh-agent</code>, escribiendo la contraseña para cada clave. El problema es que necesitarías hacer esto cada vez que reinicies tu computadora, lo cual se vuelve tedioso rápidamente.</p><p>Una mejor solución es automatizar la adición y guardado de claves y especificar qué clave utilizar cuando se ingrese a ciertos servidores.</p><h3 id="ssh-config"><strong><strong>SSH <code>config</code></strong></strong></h3><p>Entra SSH <code>config</code>, &nbsp;que es un archivo de configuración por-usuario para la comunicación SSH. Crea un nuevo archivo: <code>~/.ssh/config</code> y ábrelo para escribir:</p><pre><code class="language-bash">nano ~/.ssh/config</code></pre><h3 id="administrando-nombres-personalizados-de-claves-ssh"><strong>Administrando nombres personalizados de </strong>claves<strong> <strong>SSH</strong></strong></h3><p>La primera cosa que vamos a resolver usando este archivo <code>config</code> es evitar tener que agregar nombres personalizados para las claves SSH usando <code>ssh-add</code>. Asumiendo que tu clave privada se llame &nbsp;<code>~/.ssh/id_rsa</code>, agrega lo siguiente al archivo <code>config</code>:</p><pre><code class="language-bash">Host github.com
  HostName github.com
  User git
  IdentityFile ~/.ssh/id_rsa
  IdentitiesOnly yes</code></pre><p>A continuación, abre otra terminal para asegurarte que &nbsp;<code>~/.ssh/id_rsa</code> no esté en &nbsp;<code>ssh-agent</code> y corre el siguiente comando:</p><pre><code class="language-text">ssh-add -D</code></pre><p>Este comando removerá todas las claves de la sesión &nbsp;<code>ssh-agent</code> actualmente activa.</p><p>Ahora si intentas clonar un repositorio GitHub, tu archivo <code>config</code> usará la clave en <code>~/.ssh/ida_rsa</code>.</p><p>Aquí están otros ejemplos útiles de configuración:</p><pre><code class="language-bash">Host bitbucket-corporate
        HostName bitbucket.org
        User git
        IdentityFile ~/.ssh/id_rsa_corp
        IdentitiesOnly yes</code></pre><p>Ahora puedes usar &nbsp;<code>git clone git@bitbucket-corporate:company/project.git</code></p><pre><code class="language-bash">Host bitbucket-personal
        HostName bitbucket.org
        User git
        IdentityFile ~/.ssh/id_rsa_personal
        IdentitiesOnly yes</code></pre><p>Ahora puedes usar &nbsp;<code>git clone git@bitbucket-personal:username/other-pi-project.git</code></p><pre><code class="language-bash">Host myserver
        HostName ssh.username.com
        Port 1111
        IdentityFile ~/.ssh/id_rsa_personal
        IdentitiesOnly yes
        User username
        IdentitiesOnly yes</code></pre><p>Ya puedes usar SSH para ingresar a tu servidor usando <code>ssh myserver</code>. Ya no necesitarás ingresar un puerto (port) y nombre de usuario cada vez que quieras ingresar a tu servidor privado.</p><h3 id="administraci-n-de-contrase-as"><strong>Administración de contraseñas</strong></h3><p>La pieza final del rompecabezas es el manejo o administración de contraseñas. Se puede volver una tarea tediosa tener que ingresar una contraseña cada vez que inicializas una conexión SSH. Para evitar esta situación, podemos usar software de administración de contraseñas que viene con macOS y varias distribuciones de Linux.</p><p>Para este tutorial usaremos Keychain Access, un programa de macOS. Empecemos por agregar tu clave a Keychain Access pasando la opción <code>-K</code> al comando <code>ssh-add</code>:</p><pre><code class="language-bash">ssh-add -K ~/.ssh/id_rsa_whatever</code></pre><p>Ahora podrás ver tu clave SSH en Keychain Access:</p><p>Pero si quitas las claves de &nbsp;<code>ssh-agent</code> con &nbsp;<code>ssh-add -D</code> o reinicias tu computadora, esta te volverá a solicitar la contraseña y usuario cuando trates de usar SSH. Resulta que hay un obstáculo más que sortear. Abre tu archivo &nbsp;<code>config</code> usando <code>nano ~/.ssh/config</code> y agrega lo siguiente: &nbsp;</p><pre><code class="language-bash">Host *
  AddKeysToAgent yes
  UseKeychain yes</code></pre><p>Con esto, cuando sea que uses <code>ssh</code> la computadora buscará automáticamente las claves en Keychain Access. Si encuentra una, ya no se te solicitará una contraseña cada que uses SSH. Las claves también se agregan automáticamente a <code>ssh-agent</code> cada vez que reinicias tu computadora.</p><p>¡Ahora que sabes lo básico de crear nuevas claves SSH y administrar varias, sal a ponerlo en práctica! </p><p>Traducido del artículo - <a href="https://www.freecodecamp.org/news/the-ultimate-guide-to-ssh-setting-up-ssh-keys/">The ultimate guide to ssh setting up ssh keys</a></p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
