<?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[ CipherBoB - 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[ CipherBoB - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/espanol/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sun, 24 May 2026 13:55:44 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/espanol/news/author/cipherbob/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ ¿Cuál es el Content-Type correcto para JSON? Explicación del Mime Type del encabezado de la solicitud ]]>
                </title>
                <description>
                    <![CDATA[ Cada recurso utilizado en Internet tiene un tipo de medio, también conocido como tipo MIME, que significa Extensión multipropósito de correo de Internet (por sus siglas en inglés Multipurpose Internet Mail Exension). Esta información es necesaria para las transacciones entre el servidor y el cliente. El navegador necesita conocer el ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/cual-es-el-content-type-correcto-para-json-explicacion-del-mime-type-del-encabezado-de-la-solicitud/</link>
                <guid isPermaLink="false">644f5e34e59d8f07c2db34ff</guid>
                
                    <category>
                        <![CDATA[ Json ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ CipherBoB ]]>
                </dc:creator>
                <pubDate>Tue, 16 May 2023 18:45:23 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/05/5fcf4739e6787e098393bd6d.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/what-is-the-correct-content-type-for-json-request-header-mime-type-explained/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">What is the Correct Content-Type for JSON? Request Header Mime Type Explained</a>
      </p><p>Cada recurso utilizado en Internet tiene un tipo de medio, también conocido como tipo MIME, que significa Extensión multipropósito de correo de Internet (por sus siglas en inglés Multipurpose Internet Mail Exension). Esta información es necesaria para las transacciones entre el servidor y el cliente.</p><p>El navegador necesita conocer el tipo de medio de los recursos que se le envían para que pueda manejarlos correctamente.</p><p>Lo mismo ocurre con el servidor. Necesita saber el tipo de recursos que se le envían para un análisis y procesamiento precisos.</p><h2 id="-d-nde-se-declara-el-tipo-de-contenido-content-type-"><strong>¿Dónde se declara el tipo de contenido (Content-Type)?</strong></h2><p>El tipo de medio de cualquier recurso se declara en la propiedad <code>Content-Type</code> del encabezado de la solicitud (en el cliente, al realizar una solicitud al servidor) o en el encabezado de respuesta (en el servidor, al enviar una respuesta).</p><p>Sin declarar explícitamente el tipo de contenido de un recurso, el cliente puede intentar detectar automáticamente el tipo, pero el resultado puede no ser exacto. Por eso es importante declararlo explícitamente.</p><h2 id="tipos-de-medios"><strong>Tipos de medios</strong></h2><p>Los tipos de medios existen en varias formas. Se clasifican en varios grupos:</p><ul><li>application (aplicación)</li><li>audio</li><li>font (fuente)</li><li>example (ejemplo)</li><li>image (imagen)</li><li>message (mensaje)</li><li>model (modelo)</li><li>multipart</li><li>text (texto)</li><li>y video</li></ul><p>Estas categorías también tienen sus tipos. Por ejemplo, <code>application/json</code>es un tipo dentro de <code>application</code>y <code>text/html</code>es un tipo dentro de <code>text</code>.</p><p>Puedes encontrar una lista completa de tipos de medios en los tipos de medios de la <a href="https://www.iana.org/assignments/media-types/media-types.xhtml">IANA</a> (un organismo que coordina algunos de los elementos clave en Internet).</p><p>Todos estos tipos cubren varios tipos de datos como texto, audio, imágenes, HTML y muchos más tipos que se utilizan en Internet.</p><h2 id="el-navegador-necesita-saber-el-tipo-de-medio-de-un-recurso"><strong>El navegador necesita saber el tipo de medio de un recurso</strong></h2><p>Como mencioné anteriormente, el navegador necesita saber qué tipo de contenido recibe. He aquí un ejemplo para ilustrar eso.</p><p>El siguiente código es un servidor Node que sirve un archivo HTML:</p><pre><code class="language-js">const http = require("http");
const fs = require("fs");
const path = require("path");

const server = http.createServer(function (req, res) {
	const filePath = path.join(__dirname, "index.html");
	var stat = fs.statSync(filePath);

	res.writeHead(200, {
		"Content-Type": "text/css",
		"Content-Length": stat.size,
	});

	const readStream = fs.createReadStream(filePath);
	readStream.pipe(res);
});

server.listen(5000);

console.log("Node.js web server at port 5000 is running..");
</code></pre><p>No te preocupes por los detalles del código. Todo lo que debe preocuparte es el archivo <code>index.htm</code> que estamos sirviendo y que el <code>Content-Type</code>es <code>text/css</code>.</p><p>Aquí está el contenido del <code>index.html</code>:</p><pre><code class="language-html">&lt;h1&gt;Homepage&lt;/h1&gt;
</code></pre><p>Por supuesto, un documento HTML es diferente de un archivo CSS. Aquí está el resultado de <code>localhost:5000</code>cuando el servidor está iniciado:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/12/Screenshot-2020-12-08-at-10.12.32.png" class="kg-image" alt="Screenshot-2020-12-08-at-10.12.32" width="600" height="400" loading="lazy"></figure><p>También puedes confirmar la respuesta obtenida al verificar los encabezados en la pestaña de red de DevTools.</p><p>Aquí está el resultado en un navegador Chrome:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/12/Screenshot-2020-12-08-at-10.13.34.png" class="kg-image" alt="Screenshot-2020-12-08-at-10.13.34" width="600" height="400" loading="lazy"></figure><p>El navegador obtuvo el contenido como un tipo CSS, por lo tanto, intentó tratarlo como CSS.</p><p>Además, ten en cuenta que el conocimiento completo del tipo de contenido obtenido por el navegador también reduce las vulnerabilidades de seguridad, ya que el navegador conoce los estándares de seguridad que debe implementar para esos datos.</p><p>Ahora que comprendes el concepto de tipos MIME y su importancia, pasemos a JSON.</p><h2 id="el-tipo-de-contenido-correcto-para-json"><strong>El tipo de contenido correcto para JSON</strong></h2><p>JSON tiene que ser interpretado correctamente por el navegador para ser utilizado adecuadamente. <code>text/plain</code>se usaba normalmente para JSON, pero según <a href="https://www.iana.org/assignments/media-types/media-types.xhtml">IANA</a>, el tipo MIME oficial para JSON es <code>application/json</code>.</p><p>Esto significa que cuando envías JSON al servidor o recibes JSON del servidor, siempre debe estar declarado el <code>Content-Type</code> del encabezado, como <code>application/json</code> por ser el estándar que entienden el cliente y el servidor.</p><h2 id="conclusi-n"><strong>Conclusión</strong></h2><p>Como se indicó anteriormente, el servidor (al igual que el navegador) necesita saber el tipo de datos que se le envía, por ejemplo, en una solicitud POST. Esa es la razón por la que los <code>forms</code> con archivos suelen contener el atributo <code>enctype</code> con un valor de <code>multipart/form-data</code>.</p><p>Sin codificar la solicitud de esta manera, la solicitud POST no funcionará. Además, una vez que el servidor conoce el tipo de datos que ha obtenido, sabe cómo analizar los datos codificados.</p><p>En este artículo, analizamos qué son los tipos MIME y su propósito. Además, analizamos el tipo de contenido oficial para JSON. Espero que ahora sepas por qué es importante declarar los tipos de recursos cuando se usan en Internet.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo usar Redux en ReactJS con ejemplos de la vida cotidiana ]]>
                </title>
                <description>
                    <![CDATA[ Desde que comencé a trabajar con ReactJS [https://reactjs.org/] , en  Creative-Tim [https://www.creative-tim.com/] , solo lo he usado para crear  aplicaciones de react simples [https://www.creative-tim.com/bootstrap-themes/react-themes] , o plantillas [https://www.creative-tim.com/bootstrap-themes/react-themes] , por así decirlo. He usado ReactJS solo con create-react-app [https://github.com/facebook/create-react-app] y nunca he intentado integrarlo con algo más. Muchos ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-usar-redux-en-reactjs-con-ejemplos-de-la-vida-cotidiana/</link>
                <guid isPermaLink="false">644989b6db9a5007c084a258</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ CipherBoB ]]>
                </dc:creator>
                <pubDate>Fri, 05 May 2023 01:06:31 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/04/1_hOT8TIpiXVDCK02sQkvhDQ.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-use-redux-in-reactjs-with-real-life-examples-687ab4441b85/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to use Redux in ReactJS with real-life examples</a>
      </p><p>Desde que comencé a trabajar con <a href="https://reactjs.org/" rel="noopener">ReactJS</a> , en <a href="https://www.creative-tim.com/" rel="noopener">Creative-Tim</a> , solo lo he usado para crear <a href="https://www.creative-tim.com/bootstrap-themes/react-themes" rel="noopener">aplicaciones de react simples</a> , o <a href="https://www.creative-tim.com/bootstrap-themes/react-themes" rel="noopener">plantillas</a> , por así decirlo. He usado ReactJS solo con <a href="https://github.com/facebook/create-react-app" rel="noopener">create-react-app</a> y nunca he intentado integrarlo con algo más.</p><p>Muchos de nuestros usuarios nos han preguntado a mi equipo o a mí si las plantillas creadas por mí tenían <a href="https://redux.js.org/" rel="noopener">Redux</a> . O si se crearon de tal manera que pudieran usarse con Redux. Y mi respuesta siempre era algo así como: “Todavía no he trabajado con Redux y no sé qué respuesta darte”.</p><p>Así que aquí estoy ahora, escribiendo un artículo sobre Redux y cómo debería usarse en React. Más adelante, en este artículo, agregaré Redux en uno de los proyectos en los que he trabajado durante el último y algunos años.</p><p>Es bueno saber antes de seguir adelante y pelearse con estas dos bibliotecas que:</p><ul><li>Voy a usar <a href="https://github.com/facebook/create-react-app" rel="noopener">create-react-app@2.1. </a>1 (instalado globalmente)</li><li>Estoy usando <a href="https://www.npmjs.com/package/npm" rel="noopener">npm@6.4.1</a></li><li>Mi versión <a href="https://nodejs.org/en/" rel="noopener">de Node.js</a> en el momento de escribir esta publicación era 10.13.0 (LTS)</li><li>Si quieres usar <a href="https://webpack.js.org/" rel="noopener">Webpack</a> en su lugar, puedes leer mi <a href="https://medium.freecodecamp.org/how-to-use-reactjs-with-webpack-4-babel-7-and-material-design-ff754586f618" rel="noopener">artículo de Webpack</a> y combinar lo que te muestro allí con lo que te mostraré aquí.</li></ul><h3 id="crear-un-nuevo-proyecto-basado-en-reactjs-y-agregarle-redux"><strong>Crear un nuevo proyecto basado en ReactJS y agregarle Redux</strong></h3><p>Lo primero es lo primero, creamos una nueva aplicación de react, cd en ella e iniciamos.</p><pre><code class="language-bash">create-react-app react-redux-tutorial
cd react-redux-tutorial
npm start</code></pre><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/nDaQRa3VplnG8gqJg08kGNkwpeSvlad2s30B" class="kg-image" alt="nDaQRa3VplnG8gqJg08kGNkwpeSvlad2s30B" width="800" height="500" loading="lazy"><figcaption>default <strong style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 700; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 17.6px; vertical-align: baseline; color: var(--gray85);">create-react-app </strong>output of <strong style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 700; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 17.6px; vertical-align: baseline; color: var(--gray85);">npm start</strong></figcaption></figure><p>Como podemos ver, create-react-app nos proporciona una plantilla muy básica con un párrafo, un ancla al sitio web de React y el icono oficial de ReactJS rotando.</p><p>No os he dicho para qué vamos a usar Redux, o qué estamos haciendo aquí. Ha sido porque necesitaba la imagen gif de arriba.</p><p>Para que este tutorial sea ligero y fácil de entender, no vamos a construir algo muy complejo. Vamos a usar Redux para hacer que la imagen de React anterior se detenga o comience a girar.</p><p>Dicho esto, sigamos adelante y agreguemos los siguientes paquetes <strong><strong>de Redux :</strong></strong></p><pre><code class="language-bash">npm install --save redux react-redux</code></pre><p><a href="https://redux.js.org/" rel="noopener">redux v4.0.1</a></p><ul><li>Lo que hace Redux en un sentido muy general, es crear un estado global para toda la aplicación, al que puede acceder cualquiera de sus componentes.</li><li>Es una biblioteca de gestión de estado.</li><li>Solo tiene un estado para toda su aplicación, y no estados para cada uno de sus componentes</li></ul><p><a href="https://www.npmjs.com/package/react-redux" rel="noopener">react-redux v5.1.1</a></p><ul><li>Esto se usa para que podamos acceder a los datos de Redux y modificarlos enviando acciones a Redux, en realidad no a Redux, pero llegaremos a esto.</li><li>Según la documentación oficial: P<em><em>ermite que sus componentes React lean datos de un</em> almacén<em> Redux y envíen acciones a</em>l almacén<em> para actualizar datos</em></em></li></ul><p><strong><strong>NOTA</strong></strong> : S<em><em>i tiene</em>s<em> problemas con el comando anterior, intent</em>a<em> instalar los paquetes por separado</em></em></p><p>Cuando trabajes con Redux, necesitarás tres cosas principales:</p><ul><li><a href="https://redux.js.org/basics/actions" rel="noopener">acciones</a>: Estos son objetos que deben tener dos propiedades, una que describe el <strong><strong>tipo</strong></strong> de acción y otra que describe lo que debe cambiarse en el estado de la aplicación.</li><li><a href="https://redux.js.org/basics/reducers" rel="noopener">reductores</a>: Son funciones que implementan el comportamiento de las acciones. Cambian el estado de la aplicación, según la descripción de la acción y la descripción del cambio de estado.</li><li><a href="https://redux.js.org/basics/store">almacén</a>: Reúne las acciones y los reductores, mantiene y cambia el estado de toda la aplicación; solo hay un almacén.</li></ul><p>Como he dicho antes, vamos a detener y comenzar a girar el logotipo de React. Esto significa que vamos a necesitar dos acciones de la siguiente manera:</p><p>1 — Comandos de Linux/Mac</p><pre><code class="language-bash">mkdir src/actions
touch src/actions/startAction.js
touch src/actions/stopAction.js</code></pre><p>2 — Comandos de Windows</p><pre><code class="language-bash">mkdir src\actions
echo "" &gt; src\actions\startAction.js
echo "" &gt; src\actions\stopAction.js</code></pre><p>Ahora editemos <strong><strong>src/actions/startAction.js</strong></strong> de la siguiente manera:</p><pre><code class="language-js">export const startAction = {
  type: "rotate",
  payload: true
};</code></pre><p>A continuación, vamos a decirle a nuestro reductor que el tipo de acción es sobre la <em><em>rotación</em></em> ( <strong><strong>rotate</strong></strong> ) del logo de React. Y el estado para la rotación del logotipo de React debe cambiarse a <strong><strong>verdadero</strong></strong> : Queremos que el logotipo comience a girar.</p><p>Entonces editemos <strong><strong>src/actions/stopAction.js</strong></strong> de la siguiente manera:</p><pre><code class="language-js">export const stopAction = {
  type: "rotate",
  payload: false
};</code></pre><p>Ahora, vamos a decirle a nuestro reductor que el tipo de acción es sobre la <em><em>rotación</em></em> (<strong><strong>rotate</strong></strong>) del logo de React. Y el estado para la rotación del logotipo de React debe cambiarse a <strong><strong>falso</strong></strong> : Queremos que el logotipo deje de girar.</p><p>También creamos el reductor para nuestra aplicación:</p><p>1 — Comandos de Linux/Mac</p><pre><code class="language-bash">mkdir src/reducers
touch src/reducers/rotateReducer.js</code></pre><p>2 — Comandos de Windows</p><pre><code class="language-bash">mkdir src\reducers
echo "" &gt; src\reducers\rotateReducer.js</code></pre><p>Y, agregamos el siguiente código dentro de él:</p><pre><code class="language-js">export default (state, action) =&gt; {
  switch (action.type) {
    case "rotate":
      return {
        rotating: action.payload
      };
    default:
      return state;
  }
};</code></pre><p>Entonces, el reductor recibirá nuestras dos acciones, ambas del tipo <strong><strong>rotar,</strong></strong> y ambas cambian el mismo estado en la aplicación, que es <em><em>state.rotating</em></em> . Según la carga útil de estas acciones, <em><em>state.rotating</em></em> cambiará a <strong><strong>true</strong></strong> o <strong><strong>false</strong></strong> .</p><p>He agregado un caso <strong><strong>predeterminado</strong></strong> , que mantendrá el estado inalterado si el tipo de acción es no <strong><strong>rotar</strong></strong> . El valor predeterminado está allí en caso de que creemos una acción y olvidemos agregar un caso para esa acción. De esta manera, no eliminamos todo el estado de la aplicación, simplemente no hacemos nada y mantenemos lo que teníamos.</p><p>Lo último que debemos hacer es crear nuestro almacén para toda la aplicación. Dado que solo hay un almacén/un estado para toda la aplicación, no vamos a crear una nueva carpeta para el almacén. Si quieres, puedes crear una carpeta nueva para el almacén y agregarla allí, pero no es como con las acciones, por ejemplo, donde puedes tener múltiples acciones y parece mejor mantenerlas dentro de una carpeta.</p><p>Dicho esto, vamos a ejecutar este comando:</p><p>1 — Comando Linux/Mac</p><pre><code class="language-bash">touch src/store.js</code></pre><p>2 — Comando de Windows</p><pre><code class="language-bash">echo "" &gt; src\store.js</code></pre><p>Y también agregamos el siguiente código dentro de él:</p><pre><code class="language-js">import { createStore } from "redux";
import rotateReducer from "reducers/rotateReducer";

function configureStore(state = { rotating: true }) {
  return createStore(rotateReducer,state);
}

export default configureStore;</code></pre><p>Entonces, creamos una función llamada <strong><strong>configureStore</strong></strong> en la que enviamos un estado predeterminado, y creamos nuestro almacén usando el reductor creado y el estado predeterminado.</p><p>No estoy seguro si has visto mis importaciones, usan rutas absolutas, por lo que es posible que tengas algunos errores debido a esto. La solución para esto es una de las dos:</p><p>Cualquiera</p><p>1 — Agrega un archivo .env a tu aplicación así:</p><pre><code class="language-bash">echo "NODE_PATH=./src" &gt; .env</code></pre><p>O</p><p>2 — Instala cross-env globalmente y cambia el script de inicio del archivo package.json así:</p><pre><code class="language-bash">npm install -g cross-env</code></pre><p>Y dentro del paquete.json</p><pre><code class="language-json">"start": "NODE_PATH=./src react-scripts start",</code></pre><p>Ahora que hemos configurado nuestro almacén, nuestras acciones y nuestro reductor, necesitamos agregar una nueva clase dentro del archivo <strong><strong>src/App.css</strong></strong> . Esta clase pausará la animación giratoria del logo.</p><p>Así que vamos a escribir lo siguiente dentro de <strong><strong>src/App.css</strong></strong> :</p><pre><code class="language-css">.App-logo-paused {
  animation-play-state: paused;
}</code></pre><p>Entonces, tu archivo <strong><strong>App.css</strong></strong> debería verse así:</p><pre><code class="language-css">.App {
  text-align: center;
}

.App-logo {
  animation: App-logo-spin infinite 20s linear;
  height: 40vmin;
}

/* new class here */
.App-logo-paused {
  animation-play-state: paused;
}

.App-header {
  background-color: #282c34;
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
  justify-content: center;
  font-size: calc(10px + 2vmin);
  color: white;
}

.App-link {
  color: #61dafb;
}

@keyframes App-logo-spin {
  from {
    transform: rotate(0deg);
  }
  to {
    transform: rotate(360deg);
  }
}</code></pre><p>Ahora, solo necesitamos modificar nuestro archivo <strong><strong>src/App.js</strong></strong> para que escuche el estado de nuestro almacén. Y al hacer clic en el logotipo, llama a una de las acciones de inicio o detención.</p><p>Lo primero es lo primero, necesitamos conectar nuestro componente a nuestro almacén redux para importar <strong><strong>la conexión</strong></strong> desde <strong><strong>react-redux</strong></strong> .</p><pre><code class="language-js">import { connect } from "react-redux";</code></pre><p>Después de esto, exportaremos nuestro componente de aplicación a través del método de conexión de esta manera:</p><pre><code class="language-js">export default connect()(App);</code></pre><p>Para cambiar el estado del almacén redux, necesitaremos las acciones que hemos realizado anteriormente, así que importémoslas también:</p><pre><code class="language-js">import { startAction } from "actions/startAction";
import { stopAction } from "actions/stopAction";</code></pre><p>Ahora necesitamos recuperar el estado de nuestro almacén y decir que queremos que las acciones de inicio y detención se usen para cambiar el estado.</p><p>Esto se hará usando la función de conexión, que acepta dos parámetros:</p><ul><li><strong><strong>mapStateToProps:</strong></strong> Este se usa para recuperar el estado del almacén</li><li><strong><strong>mapDispatchToProps:</strong></strong> Este se usa para recuperar las acciones y enviarlas al almacén</li></ul><p>Puedes leer más sobre ellos aquí: <a href="https://github.com/reduxjs/react-redux/blob/master/docs/api.md#arguments">conectar argumentos de función de react-redux</a>.</p><p>Ahora, escribamos dentro de nuestro App.js (al final del archivo, si puedes):</p><pre><code class="language-js">const mapStateToProps = state =&gt; ({
  ...state
});

const mapDispatchToProps = dispatch =&gt; ({
  startAction: () =&gt; dispatch(startAction),
  stopAction: () =&gt; dispatch(stopAction)
});</code></pre><p>Después de esto, agreguémoslos dentro de nuestra función de conexión así:</p><pre><code class="language-js">export default connect(mapStateToProps, mapDispatchToProps)(App);</code></pre><p>Y ahora ya, dentro de nuestro componente App, podemos acceder al estado del almacén, startAction y stopAction a través de props.</p><p>Cambiemos la etiqueta <strong><strong>img </strong></strong>a:</p><pre><code class="language-jsx">&lt;img 
  src={logo} 
  className={
    "App-logo" + 
    (this.props.rotating ? "":" App-logo-paused")
  } 
  alt="logo" 
  onClick={
    this.props.rotating ? 
      this.props.stopAction : this.props.startAction
  }
/&gt;</code></pre><p>Aquí, lo que estamos diciendo es que, si el estado de rotación del almacén (<strong><strong>this.props.rotating</strong></strong> ) es verdadero, entonces solo queremos que la <strong><strong>className</strong> </strong><em><em>App-logo</em> </em>se establezca en nuestra <strong><strong>img</strong></strong> . Si eso es falso, también queremos que la clase <em><em>App-logo-paused</em></em> se establezca en <strong><strong>className</strong></strong> . De esta manera pausamos la animación.</p><p>Además, si <strong><strong>this.props.rotating</strong></strong> es <strong><strong>verdadero</strong></strong> , luego queremos enviar a nuestro almacén por la función <strong><strong>onClick</strong></strong> y volver a cambiarlo a <strong><strong>falso</strong></strong> , y viceversa.</p><p>Casi hemos terminado, pero nos hemos olvidado de algo.</p><p>Todavía no le hemos dicho a nuestra aplicación de react que tenemos un estado global o, si lo prefieres, que usamos la administración de estado redux.</p><p>Para ello, ingresamos a <strong><strong>src/index.js</strong></strong> , importamos un <strong>Provider</strong> de <strong><strong>react-redux</strong></strong> y el almacén recién creado así:</p><pre><code class="language-js">import { Provider } from "react-redux";

import configureStore from "store";</code></pre><ul><li><a href="https://react-redux.js.org/docs/api/provider" rel="noopener">Provider</a> : Hace que el almacén Redux esté disponible para cualquier componente anidado que se haya incluido en la función de conexión</li></ul><p>Después de esto, en lugar de renderizar nuestro componente App directamente, lo renderizamos a través de nuestro Provider usando el almacén que hemos creado así:</p><pre><code class="language-js">ReactDOM.render(
  &lt;Provider store={configureStore()}&gt;
    &lt;App /&gt;
  &lt;/Provider&gt;,
  document.getElementById('root')
);</code></pre><p>Aquí podríamos haber usado la función <strong><strong>configureStore</strong></strong> con algún otro estado, por ejemplo <strong><strong><em><em>configureStore({ro</em></em></strong><em>t</em><strong><em><em>ating: false })</em></em></strong></strong> .</p><p>Entonces, el <strong><strong>index.js</strong></strong> debería verse así:</p><pre><code class="language-js">import React from 'react';
import ReactDOM from 'react-dom';
// new imports start (Inicio nuevas importaciones)
import { Provider } from "react-redux";

import configureStore from "store";
// new imports stop (Fin de nuevas importaciones)

import './index.css';

import App from './App';
import * as serviceWorker from './serviceWorker';

// changed the render (Cambiado el render)
ReactDOM.render(
  &lt;Provider store={configureStore()}&gt;
    &lt;App /&gt;
  &lt;/Provider&gt;,
  document.getElementById('root')
);
// changed the render (Cambiado el render)

serviceWorker.unregister();</code></pre><p>Avancemos y veamos si nuestra aplicación redux funciona:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/cOdx8xHzZjMmqEYSTgVkkPSXkG925Hwewoxj" class="kg-image" alt="cOdx8xHzZjMmqEYSTgVkkPSXkG925Hwewoxj" width="800" height="500" loading="lazy"><figcaption><strong style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 700; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 17.6px; vertical-align: baseline; color: var(--gray85);">react</strong> and <strong style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 700; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 17.6px; vertical-align: baseline; color: var(--gray85);">redux</strong> in action</figcaption></figure><h3 id="uso-de-creadores-de-acciones"><strong>Uso de creadores de acciones</strong></h3><p>Opcionalmente, en lugar de <strong><strong>acciones</strong></strong> , podemos usar <a href="https://redux.js.org/basics/actions#action-creators" rel="noopener">creadores de acciones</a> , que son funciones que crean acciones.</p><p>De esta forma, podemos combinar nuestras dos acciones en una sola función y reducir un poco nuestro código.</p><p>Entonces, sigamos adelante y creemos un nuevo archivo:</p><p>1 — Comando Linux/Mac</p><pre><code class="language-bash">touch src/actions/rotateAction.js</code></pre><p>2 — Comando de Windows</p><pre><code class="language-bash">echo "" &gt; src\actions\rotateAction.js</code></pre><p>Y añadimos este código:</p><pre><code class="language-jsx">const rotateAction = (payload) =&gt; {
  return {
    type: "rotate",
    payload
  }
}
export default rotateAction;</code></pre><p>Vamos a enviar una acción de tipo rotar, con un payload que vamos a obtener en el componente App.</p><p>Dentro del componente src/App.js, necesitamos importar nuestro nuevo creador de acciones:</p><pre><code class="language-js">import rotateAction from "actions/rotateAction";</code></pre><p>Agregamos la nueva función a mapDispatchToProps así:</p><p>rotateAction: Recibirá una (payload) y enviará la acción rotateAction con la payload</p><p>Cambiamos la función <strong><strong>onClick</strong></strong> a:</p><pre><code class="language-js">onClick={() =&gt; this.props.rotateAction(!this.props.rotating)}</code></pre><p>Y finalmente, agregamos nuestro nuevo creador de acciones al <strong><strong>mapDispatchToProps</strong></strong> de esta manera:</p><pre><code class="language-js">rotateAction: (payload) =&gt; dispatch(rotateAction(payload))</code></pre><p>También podemos eliminar las importaciones antiguas para las acciones antiguas y eliminarlas también de <strong><strong>mapDispatchToProps .</strong></strong></p><p>Así es como debería verse el nuevo src/App.js:</p><pre><code class="language-jsx">import React, { Component } from 'react';
// new lines from here (Nuevas líneas desde aquí)
import { connect } from "react-redux";
import rotateAction from "actions/rotateAction";

//// new lines to here (Nuevas líneas hasta aquí)

import logo from './logo.svg';
import './App.css';

class App extends Component {
  render() {
    console.log(this.props);
    return (
      &lt;div className="App"&gt;
        &lt;header className="App-header"&gt;
          &lt;img
            src={logo}
            className={
              "App-logo" +
              (this.props.rotating ? "":" App-logo-paused")
            }
            alt="logo"
            onClick={
              () =&gt; this.props.rotateAction(!this.props.rotating)
            }
          /&gt;
          &lt;p&gt;
            Edit &lt;code&gt;src/App.js&lt;/code&gt; and save to reload.
          &lt;/p&gt;
          &lt;a
            className="App-link"
            href="https://reactjs.org"
            target="_blank"
            rel="noopener noreferrer"
          &gt;
            Learn React
          &lt;/a&gt;
        &lt;/header&gt;
      &lt;/div&gt;
    );
  }
}

const mapStateToProps = state =&gt; ({
  ...state
});
const mapDispatchToProps = dispatch =&gt; ({
  rotateAction: (payload) =&gt; dispatch(rotateAction(payload))
});

export default connect(mapStateToProps, mapDispatchToProps)(App);</code></pre><h3 id="un-ejemplo-de-la-vida-cotidiana-con-paper-dashboard-react"><strong>Un ejemplo de la vida cotidiana con <a href="https://www.creative-tim.com/product/paper-dashboard-react" rel="noopener">Paper Dashboard React</a></strong></h3><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/356UctzmEu8euFGJLpMVitFUDLy3LduQQTl4" class="kg-image" alt="356UctzmEu8euFGJLpMVitFUDLy3LduQQTl4" width="800" height="409" loading="lazy"><figcaption><strong style="box-sizing: inherit; margin: 0px; padding: 0px; border: 0px; font-style: inherit; font-variant: inherit; font-weight: 700; font-stretch: inherit; line-height: inherit; font-family: inherit; font-size: 17.6px; vertical-align: baseline; color: var(--gray85);">Paper Dashboard React</strong> — Product Gif</figcaption></figure><p>Como puedes ver en la imagen gif de arriba, estoy usando el menú de la derecha para cambiar los colores del menú de la izquierda. Esto se logra mediante el uso de estados de componentes y pasando ese estado de un componente principal a los dos menús y algunas funciones para cambiar ese estado.</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://cdn-media-1.freecodecamp.org/images/V3KhG508UOWnU1CA2FFtKEACx7vU3BRyDfyQ" class="kg-image" alt="V3KhG508UOWnU1CA2FFtKEACx7vU3BRyDfyQ" width="800" height="188" loading="lazy"><figcaption>small diagram on how the app works at the moment</figcaption></figure><p>Pensé que sería un buen ejemplo tomar este producto y reemplazar los estados de los componentes con Redux.</p><p>Puedes conseguirlo de estas 3 formas:</p><ol><li>Descargar desde <a href="https://www.creative-tim.com/product/paper-dashboard-react" rel="noopener">creative-tim.com</a></li><li>Descargar desde <a href="https://github.com/creativetimofficial/paper-dashboard-react" rel="noopener">Github</a></li><li>Clonar de Github:</li></ol><pre><code class="language-bash">git clone https://github.com/creativetimofficial/paper-dashboard-react.git</code></pre><p>Ahora que tenemos este producto, vamos a entrar en el directorio e instalar de nuevo redux y react-redux:</p><pre><code class="language-bash">npm install --save redux react-redux</code></pre><p>Después de esto, necesitamos crear las acciones. Dado que en el menú de la derecha tenemos 2 colores que configuran el fondo del menú de la izquierda y 5 colores que cambian el color de los enlaces, necesitamos 7 acciones o 2 creadores de acciones, y vamos con esta segunda opción ya que requiere un poco menos de código:</p><p>1 — Comandos de Linux/Mac</p><pre><code class="language-bash">mkdir src/actions
touch src/actions/setBgAction.js
touch src/actions/setColorAction.js</code></pre><p>2 — Comandos de Windows</p><pre><code class="language-bash">mkdir src\actions
echo "" &gt; src\actions\setBgAction.js
echo "" &gt; src\actions\setColorAction.js</code></pre><p>Después de esto, vamos a crear el código de las acciones de la siguiente manera:</p><p>— <strong><strong>src/actions/setBgAction.js</strong></strong></p><pre><code class="language-js">const setBgAction = (payload) =&gt; {
  return {
    type: "bgChange",
    payload
  }
}
export default setBgAction;</code></pre><p>— <strong><strong>src/actions/setColorAction.js</strong></strong></p><pre><code class="language-js">const setColorAction = (payload) =&gt; {
  return {
    type: "colorChange",
    payload
  }
}
export default setColorAction;</code></pre><p>Ahora, como en la primera parte, necesitamos el reductor:</p><p>1 — Comandos de Linux/Mac</p><pre><code class="language-bash">mkdir src/reducers
touch src/reducers/rootReducer.js</code></pre><p>2 — Comandos de Windows</p><pre><code class="language-bash">mkdir src\reducers
echo "" &gt; src\reducers\rootReducer.js</code></pre><p>Y el código para el reductor:</p><pre><code class="language-js">export default (state, action) =&gt; {
  switch (action.type) {
    case "bgChange":
      return {
        ...state,
        bgColor: action.payload
      };
    case "colorChange":
      return {
        ...state,
        activeColor: action.payload
      };
    default:
      return state;
  }
};</code></pre><p>Cómo puedes ver aquí, a diferencia de nuestro primer ejemplo, queremos mantener nuestro estado anterior y actualizar su contenido.</p><p>También necesitamos el almacén:</p><p>1 — Comando Linux/Mac</p><pre><code class="language-bash">touch src/store.js</code></pre><p>2 — Comando de Windows</p><pre><code class="language-bash">echo "" &gt; src\store.js</code></pre><p>El código para ello:</p><pre><code class="language-js">import { createStore } from "redux";
import rootReducer from "reducers/rootReducer";

function configureStore(state = { bgColor: "black", activeColor: "info" }) {
  return createStore(rootReducer,state);
}
export default configureStore;</code></pre><p>Dentro de src/index.js necesitamos:</p><pre><code class="language-js">// new imports start (Inicio de nuevas importaciones)
import { Provider } from "react-redux";

import configureStore from "store";
// new imports stop (Fin de nuevas importaciones)</code></pre><p>Y también, cambia la función <strong><strong>de renderizado</strong></strong> :</p><pre><code class="language-js">ReactDOM.render(
  &lt;Provider store={configureStore()}&gt;
    &lt;Router history={hist}&gt;
      &lt;Switch&gt;
        {indexRoutes.map((prop, key) =&gt; {
          return &lt;Route path={prop.path} key={key} component={prop.component} /&gt;;
        })}
      &lt;/Switch&gt;
    &lt;/Router&gt;
  &lt;/Provider&gt;,
  document.getElementById("root")
);</code></pre><p>Entonces, el archivo <strong><strong>index.js</strong></strong> debería verse así:</p><pre><code class="language-js">import React from "react";
import ReactDOM from "react-dom";
import { createBrowserHistory } from "history";
import { Router, Route, Switch } from "react-router-dom";
// new imports start (Inicio de nuevas importaciones)
import { Provider } from "react-redux";

import configureStore from "store";
// new imports stop (Fin de nuevas importaciones)

import "bootstrap/dist/css/bootstrap.css";
import "assets/scss/paper-dashboard.scss";
import "assets/demo/demo.css";

import indexRoutes from "routes/index.jsx";

const hist = createBrowserHistory();

ReactDOM.render(
  &lt;Provider store={configureStore()}&gt;
    &lt;Router history={hist}&gt;
      &lt;Switch&gt;
        {indexRoutes.map((prop, key) =&gt; {
          return &lt;Route path={prop.path} key={key} component={prop.component} /&gt;;
        })}
      &lt;/Switch&gt;
    &lt;/Router&gt;
  &lt;/Provider&gt;,
  document.getElementById("root")
);</code></pre><p>Ahora necesitamos hacer algunos cambios dentro de <strong><strong>src/layouts/Dashboard/Dashboard.jsx</strong></strong> . Necesitamos eliminar el estado y las funciones que cambian el estado. Así que adelante, <strong><strong>elimin</strong>a<strong> estos fragmentos de código:</strong></strong></p><p>El constructor (entre las líneas 16 y 22):</p><pre><code class="language-jsx">constructor(props){
  super(props);
  this.state = {
    backgroundColor: "black",
    activeColor: "info",
  }
}</code></pre><p>Las funciones de estado (entre las líneas 41 y 46):</p><pre><code class="language-jsx">handleActiveClick = (color) =&gt; {
    this.setState({ activeColor: color });
  }
handleBgClick = (color) =&gt; {
  this.setState({ backgroundColor: color });
}</code></pre><p>Los accesorios <strong><strong>bgColor</strong></strong> y <strong><strong>activeColor</strong></strong> de la barra lateral (líneas 53 y 54):</p><pre><code class="language-jsx">bgColor={this.state.backgroundColor}
activeColor={this.state.activeColor}</code></pre><p>Todos los accesorios de FixedPlugin (entre las líneas 59–62):</p><pre><code class="language-jsx">bgColor={this.state.backgroundColor}
activeColor={this.state.activeColor}
handleActiveClick={this.handleActiveClick}
handleBgClick={this.handleBgClick}</code></pre><p>Entonces, nos quedamos con este código dentro del componente de diseño del Dashboard (Panel de control):</p><pre><code class="language-jsx">import React from "react";
// javascript plugin used to create scrollbars on windows
// plugin de javascript que se usa para crear barras de desplazamiento en windows 
import PerfectScrollbar from "perfect-scrollbar";
import { Route, Switch, Redirect } from "react-router-dom";

import Header from "components/Header/Header.jsx";
import Footer from "components/Footer/Footer.jsx";
import Sidebar from "components/Sidebar/Sidebar.jsx";
import FixedPlugin from "components/FixedPlugin/FixedPlugin.jsx";

import dashboardRoutes from "routes/dashboard.jsx";

var ps;

class Dashboard extends React.Component {
  componentDidMount() {
    if (navigator.platform.indexOf("Win") &gt; -1) {
      ps = new PerfectScrollbar(this.refs.mainPanel);
      document.body.classList.toggle("perfect-scrollbar-on");
    }
  }
  componentWillUnmount() {
    if (navigator.platform.indexOf("Win") &gt; -1) {
      ps.destroy();
      document.body.classList.toggle("perfect-scrollbar-on");
    }
  }
  componentDidUpdate(e) {
    if (e.history.action === "PUSH") {
      this.refs.mainPanel.scrollTop = 0;
      document.scrollingElement.scrollTop = 0;
    }
  }
  render() {
    return (
      &lt;div className="wrapper"&gt;
        &lt;Sidebar
          {...this.props}
          routes={dashboardRoutes}
        /&gt;
        &lt;div className="main-panel" ref="mainPanel"&gt;
          &lt;Header {...this.props} /&gt;
          &lt;Switch&gt;
            {dashboardRoutes.map((prop, key) =&gt; {
              if (prop.pro) {
                return null;
              }
              if (prop.redirect) {
                return &lt;Redirect from={prop.path} to={prop.pathTo} key={key} /&gt;;
              }
              return (
                &lt;Route path={prop.path} component={prop.component} key={key} /&gt;
              );
            })}
          &lt;/Switch&gt;
          &lt;Footer fluid /&gt;
        &lt;/div&gt;
        &lt;FixedPlugin /&gt;
      &lt;/div&gt;
    );
  }
}

export default Dashboard;</code></pre><p>Ahora necesitamos conectar los componentes <strong><strong>Sidebar</strong></strong> y <strong><strong>FixedPlugin</strong></strong> al almacén.</p><p>En <strong><strong>src/components/Sidebar/Sidebar.jsx</strong></strong> :</p><pre><code class="language-jsx">import { connect } from "react-redux";</code></pre><p>Y cambiar la exportación (export) a:</p><pre><code class="language-jsx">const mapStateToProps = state =&gt; ({
  ...state
});

export default connect(mapStateToProps)(Sidebar);</code></pre><p>En <strong><strong>src/components/FixedPlugin/FixedPlugin.jsx</strong></strong> :</p><pre><code class="language-jsx">import { connect } from "react-redux";
import setBgAction from "actions/setBgAction";
import setColorAction from "actions/setColorAction";</code></pre><p>La exportación ahora debería ser:</p><pre><code class="language-jsx">const mapStateToProps = state =&gt; ({
  ...state
});

const mapDispatchToProps = dispatch =&gt; ({
  setBgAction: (payload) =&gt; dispatch(setBgAction(payload)),
  setColorAction: (payload) =&gt; dispatch(setColorAction(payload))
});

export default connect(mapStateToProps, mapDispatchToProps)(FixedPlugin);</code></pre><p>Y Vamos a tener estos próximos cambios:</p><ul><li>en cualquier lugar donde encuentres la palabra <strong><strong>handleBgClick</strong></strong> , debemos cambiarla a <strong><strong>setBgAction</strong></strong></li><li>en cualquier lugar donde encuentres la palabra <strong><strong>handleActiveClick</strong></strong> , debemos cambiarla a <strong><strong>setColorAction</strong></strong></li></ul><p>Entonces, el componente FixedPlugin ahora debería verse así:</p><pre><code class="language-jsx">import React, { Component } from "react";

import { connect } from "react-redux";
import setBgAction from "actions/setBgAction";
import setColorAction from "actions/setColorAction";

import Button from "components/CustomButton/CustomButton.jsx";

class FixedPlugin extends Component {
  constructor(props) {
    super(props);
    this.state = {
      classes: "dropdown show"
    };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    if (this.state.classes === "dropdown") {
      this.setState({ classes: "dropdown show" });
    } else {
      this.setState({ classes: "dropdown" });
    }
  }
  render() {
    return (
      &lt;div className="fixed-plugin"&gt;
        &lt;div className={this.state.classes}&gt;
          &lt;div onClick={this.handleClick}&gt;
            &lt;i className="fa fa-cog fa-2x" /&gt;
          &lt;/div&gt;
          &lt;ul className="dropdown-menu show"&gt;
            &lt;li className="header-title"&gt;SIDEBAR BACKGROUND&lt;/li&gt;
            &lt;li className="adjustments-line"&gt;
              &lt;div className="badge-colors text-center"&gt;
                &lt;span
                  className={
                    this.props.bgColor === "black"
                      ? "badge filter badge-dark active"
                      : "badge filter badge-dark"
                  }
                  data-color="black"
                  onClick={() =&gt; {
                    this.props.setBgAction("black");
                  }}
                /&gt;
                &lt;span
                  className={
                    this.props.bgColor === "white"
                      ? "badge filter badge-light active"
                      : "badge filter badge-light"
                  }
                  data-color="white"
                  onClick={() =&gt; {
                    this.props.setBgAction("white");
                  }}
                /&gt;
              &lt;/div&gt;
            &lt;/li&gt;
            &lt;li className="header-title"&gt;SIDEBAR ACTIVE COLOR&lt;/li&gt;
            &lt;li className="adjustments-line"&gt;
              &lt;div className="badge-colors text-center"&gt;
                &lt;span
                  className={
                    this.props.activeColor === "primary"
                      ? "badge filter badge-primary active"
                      : "badge filter badge-primary"
                  }
                  data-color="primary"
                  onClick={() =&gt; {
                    this.props.setColorAction("primary");
                  }}
                /&gt;
                &lt;span
                  className={
                    this.props.activeColor === "info"
                      ? "badge filter badge-info active"
                      : "badge filter badge-info"
                  }
                  data-color="info"
                  onClick={() =&gt; {
                    this.props.setColorAction("info");
                  }}
                /&gt;
                &lt;span
                  className={
                    this.props.activeColor === "success"
                      ? "badge filter badge-success active"
                      : "badge filter badge-success"
                  }
                  data-color="success"
                  onClick={() =&gt; {
                    this.props.setColorAction("success");
                  }}
                /&gt;
                &lt;span
                  className={
                    this.props.activeColor === "warning"
                      ? "badge filter badge-warning active"
                      : "badge filter badge-warning"
                  }
                  data-color="warning"
                  onClick={() =&gt; {
                    this.props.setColorAction("warning");
                  }}
                /&gt;
                &lt;span
                  className={
                    this.props.activeColor === "danger"
                      ? "badge filter badge-danger active"
                      : "badge filter badge-danger"
                  }
                  data-color="danger"
                  onClick={() =&gt; {
                    this.props.setColorAction("danger");
                  }}
                /&gt;
              &lt;/div&gt;
            &lt;/li&gt;
            &lt;li className="button-container"&gt;
              &lt;Button
                href="https://www.creative-tim.com/product/paper-dashboard-react"
                color="primary"
                block
                round
              &gt;
                Download now
              &lt;/Button&gt;
            &lt;/li&gt;
            &lt;li className="button-container"&gt;
              &lt;Button
                href="https://www.creative-tim.com/product/paper-dashboard-react/#/documentation/tutorial"
                color="default"
                block
                round
                outline
              &gt;
                &lt;i className="nc-icon nc-paper"&gt;&lt;/i&gt; Documentation
              &lt;/Button&gt;
            &lt;/li&gt;
            &lt;li className="header-title"&gt;Want more components?&lt;/li&gt;
            &lt;li className="button-container"&gt;
              &lt;Button
                href="https://www.creative-tim.com/product/paper-dashboard-pro-react"
                color="danger"
                block
                round
                disabled
              &gt;
                Get pro version
              &lt;/Button&gt;
            &lt;/li&gt;
          &lt;/ul&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    );
  }
}

const mapStateToProps = state =&gt; ({
  ...state
});

const mapDispatchToProps = dispatch =&gt; ({
  setBgAction: (payload) =&gt; dispatch(setBgAction(payload)),
  setColorAction: (payload) =&gt; dispatch(setColorAction(payload))
});

export default connect(mapStateToProps, mapDispatchToProps)(FixedPlugin);</code></pre><p>Y hemos terminado, puedes iniciar el proyecto y ver cómo funciona todo bien:</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/Pxtk6P8ssePiK2LaAmOuG4tvn8SCXwJPVKs3" class="kg-image" alt="Pxtk6P8ssePiK2LaAmOuG4tvn8SCXwJPVKs3" width="800" height="435" loading="lazy"></figure><h3 id="reductores-m-ltiples"><strong>Reductores múltiples</strong></h3><p>Como puedes tener múltiples acciones, puedes tener múltiples reductores. Lo único que necesitas es combinarlos, lo veremos un poco más abajo.</p><p>Avancemos y creemos dos nuevos reductores para nuestra aplicación, uno para setBgAction <strong><strong>y</strong></strong> otro para <strong><strong>setColorAction</strong></strong> :</p><p>1 — Comandos de Linux/Mac</p><pre><code class="language-bash">touch src/reducers/bgReducer.js
touch src/reducers/colorReducer.js</code></pre><p>2 — Comandos de Windows</p><pre><code class="language-bash">echo "" &gt; src\reducers\bgReducer.js
echo "" &gt; src\reducers\colorReducer.js</code></pre><p>Después de esto, vamos a crear el código de los reductores de la siguiente manera:</p><p>— <strong><strong>src/reductores/bgReducer.js</strong></strong></p><pre><code class="language-js">export default (state = {}, action) =&gt; {
  switch (action.type) {
    case "bgChange":
      return {
        ...state,
        bgColor: action.payload
      };
    default:
      return state;
  }
};</code></pre><p>— <strong><strong>src/reductores/colorReducer.js</strong></strong></p><pre><code class="language-js">export default (state = {} , action) =&gt; {
  switch (action.type) {
    case "colorChange":
      return {
        ...state,
        activeColor: action.payload
      };
    default:
      return state;
  }
};</code></pre><p>Cuando trabajes con reductores combinados, debes agregar un <strong><strong>estado predeterminado</strong></strong> en cada uno de los reductores que se van a combinar. En mi caso, he elegido un objeto vacío, es decir, <strong>state<strong> = {}</strong></strong> ;</p><p>Y ahora, nuestro <strong><strong>rootReducer</strong></strong> combinará a estos dos de la siguiente manera:</p><p>— <strong><strong>src/reductores/rootReducer.js</strong></strong></p><pre><code class="language-js">import { combineReducers } from 'redux';

import bgReducer from 'reducers/bgReducer';
import colorReducer from 'reducers/colorReducer';

export default combineReducers({
  activeState: colorReducer,
  bgState: bgReducer
});</code></pre><p>Por lo tanto, decimos que queremos que <strong><strong>colorReducer</strong></strong> sea referido por la propiedad <strong><strong>activeState</strong></strong> del estado de la aplicación, y <strong><strong>bgReducer</strong></strong> sea referido por la propiedad <strong><strong>bgState</strong></strong> del estado de la aplicación.</p><p>Esto significa que nuestro estado ya no se verá así:</p><pre><code class="language-js">state = {
  activeColor: "color1",
  bgColor: "color2"
}</code></pre><p>Sinó que ahora se verá así:</p><pre><code class="language-js">state = {
  activeState: {
    activeColor: "color1"
  },
  bgState: {
    bgColor: "color2"
  }
}</code></pre><p>Como hemos cambiado nuestros reductores, ahora los hemos combinado en uno sólo, y también necesitamos cambiar nuestro <strong><strong>store.js :</strong></strong></p><p>— <strong><strong>src/store.js</strong></strong></p><pre><code class="language-js">import { createStore } from "redux";
import rootReducer from "reducers/rootReducer";

// we need to pass the initial state with the new look
// necesitamos pasar el estado (state) inicial con la nueva apariencia
function configureStore(state = { bgState: {bgColor: "black"}, activeState: {activeColor: "info"} }) {
  return createStore(rootReducer,state);
}
export default configureStore;</code></pre><p>Dado que hemos cambiado la apariencia del estado, ahora debemos cambiar los accesorios dentro de los componentes <strong><strong>Sidebar</strong></strong> y <strong><strong>FixedPlugin</strong></strong> al nuevo objeto de estado:</p><p>— <strong><strong>src/components/Sidebar/Sidebar.jsx</strong></strong> :</p><p>Cambia la <strong><strong>línea 36</strong></strong> de</p><pre><code class="language-jsx">&lt;div className="sidebar" data-color={this.props.bgColor} data-active-color={this.props.activeColor}&gt;</code></pre><p>a</p><pre><code class="language-jsx">&lt;div className="sidebar" data-color={this.props.bgState.bgColor} data-active-color={this.props.activeState.activeColor}&gt;</code></pre><p>— <strong><strong>src/components/FixedPlugin/FixedPlugin.jsx</strong></strong> :</p><p>Necesitamos cambiar todos los <code><strong><strong>this.props.bgColor</strong></strong></code>a <code><strong><strong>this.props.bgState.bgColor </strong></strong></code>. Y todo el <code><strong><strong>this.props.activeColor</strong></strong></code>a <code><strong><strong>this.props.activeState.activeColor</strong></strong></code>.</p><p>Así que el nuevo código debería verse así:</p><pre><code class="language-jsx">import React, { Component } from "react";

import Button from "components/CustomButton/CustomButton.jsx";

import { connect } from "react-redux";
import setBgAction from "actions/setBgAction";
import setColorAction from "actions/setColorAction";

class FixedPlugin extends Component {
  constructor(props) {
    super(props);
    this.state = {
      classes: "dropdown show"
    };
    this.handleClick = this.handleClick.bind(this);
  }
  handleClick() {
    if (this.state.classes === "dropdown") {
      this.setState({ classes: "dropdown show" });
    } else {
      this.setState({ classes: "dropdown" });
    }
  }
  render() {
    return (
      &lt;div className="fixed-plugin"&gt;
        &lt;div className={this.state.classes}&gt;
          &lt;div onClick={this.handleClick}&gt;
            &lt;i className="fa fa-cog fa-2x" /&gt;
          &lt;/div&gt;
          &lt;ul className="dropdown-menu show"&gt;
            &lt;li className="header-title"&gt;SIDEBAR BACKGROUND&lt;/li&gt;
            &lt;li className="adjustments-line"&gt;
              &lt;div className="badge-colors text-center"&gt;
                &lt;span
                  className={
                    this.props.bgState.bgColor === "black"
                      ? "badge filter badge-dark active"
                      : "badge filter badge-dark"
                  }
                  data-color="black"
                  onClick={() =&gt; {
                    this.props.setBgAction("black");
                  }}
                /&gt;
                &lt;span
                  className={
                    this.props.bgState.bgColor === "white"
                      ? "badge filter badge-light active"
                      : "badge filter badge-light"
                  }
                  data-color="white"
                  onClick={() =&gt; {
                    this.props.setBgAction("white");
                  }}
                /&gt;
              &lt;/div&gt;
            &lt;/li&gt;
            &lt;li className="header-title"&gt;SIDEBAR ACTIVE COLOR&lt;/li&gt;
            &lt;li className="adjustments-line"&gt;
              &lt;div className="badge-colors text-center"&gt;
                &lt;span
                  className={
                    this.props.activeState.activeColor === "primary"
                      ? "badge filter badge-primary active"
                      : "badge filter badge-primary"
                  }
                  data-color="primary"
                  onClick={() =&gt; {
                    this.props.setColorAction("primary");
                  }}
                /&gt;
                &lt;span
                  className={
                    this.props.activeState.activeColor === "info"
                      ? "badge filter badge-info active"
                      : "badge filter badge-info"
                  }
                  data-color="info"
                  onClick={() =&gt; {
                    this.props.setColorAction("info");
                  }}
                /&gt;
                &lt;span
                  className={
                    this.props.activeState.activeColor === "success"
                      ? "badge filter badge-success active"
                      : "badge filter badge-success"
                  }
                  data-color="success"
                  onClick={() =&gt; {
                    this.props.setColorAction("success");
                  }}
                /&gt;
                &lt;span
                  className={
                    this.props.activeState.activeColor === "warning"
                      ? "badge filter badge-warning active"
                      : "badge filter badge-warning"
                  }
                  data-color="warning"
                  onClick={() =&gt; {
                    this.props.setColorAction("warning");
                  }}
                /&gt;
                &lt;span
                  className={
                    this.props.activeState.activeColor === "danger"
                      ? "badge filter badge-danger active"
                      : "badge filter badge-danger"
                  }
                  data-color="danger"
                  onClick={() =&gt; {
                    this.props.setColorAction("danger");
                  }}
                /&gt;
              &lt;/div&gt;
            &lt;/li&gt;
            &lt;li className="button-container"&gt;
              &lt;Button
                href="https://www.creative-tim.com/product/paper-dashboard-react"
                color="primary"
                block
                round
              &gt;
                Download now
              &lt;/Button&gt;
            &lt;/li&gt;
            &lt;li className="button-container"&gt;
              &lt;Button
                href="https://www.creative-tim.com/product/paper-dashboard-react/#/documentation/tutorial"
                color="default"
                block
                round
                outline
              &gt;
                &lt;i className="nc-icon nc-paper"&gt;&lt;/i&gt; Documentation
              &lt;/Button&gt;
            &lt;/li&gt;
            &lt;li className="header-title"&gt;Want more components?&lt;/li&gt;
            &lt;li className="button-container"&gt;
              &lt;Button
                href="https://www.creative-tim.com/product/paper-dashboard-pro-react"
                color="danger"
                block
                round
                disabled
              &gt;
                Get pro version
              &lt;/Button&gt;
            &lt;/li&gt;
          &lt;/ul&gt;
        &lt;/div&gt;
      &lt;/div&gt;
    );
  }
}

const mapStateToProps = state =&gt; ({
  ...state
});

const mapDispatchToProps = dispatch =&gt; ({
  setBgAction: (payload) =&gt; dispatch(setBgAction(payload)),
  setColorAction: (payload) =&gt; dispatch(setColorAction(payload))
});

export default connect(mapStateToProps, mapDispatchToProps)(FixedPlugin);</code></pre><p>Abramos el proyecto nuevamente con <code>npm start</code> y veamos cómo funciona todo. ¡Tachán!</p><h3 id="-gracias-por-leer-"><strong>¡Gracias por leer!</strong></h3><p>Si te ha gustado leer este tutorial, compártelo. Estoy muy interesado en escuchar tus pensamientos al respecto. Simplemente deja un comentario en este hilo y estaré más que feliz de responder.</p><p>Un agradecimiento especial también debe ir a <a href="https://medium.com/@estherfalayi" rel="noopener">Esther Falayi</a> por su <a href="https://medium.com/backticks-tildes/setting-up-a-redux-project-with-create-react-app-e363ab2329b8" rel="noopener">tutorial</a> que me ha brindado una comprensión muy necesaria sobre <strong><strong>Redux</strong></strong> .</p><p>Enlace útil:</p><ul><li>Obtén el código para este tutorial de <a href="https://github.com/creativetimofficial/react-redux-tutorial" rel="noopener">Github</a></li></ul><p>Encuéntrame en:</p><ul><li>Correo electrónico: <a href="mailto:manu@creative-tim.com" rel="noopener">manu@creative-tim.com</a></li><li>Facebook: <a href="https://www.facebook.com/NazareEmanuel" rel="noopener">https://www.facebook.com/NazareEmanuel</a></li><li>Instagram: <a href="https://www.instagram.com/manu.nazare/" rel="noopener">https://www.instagram.com/manu.nazare/</a></li><li>Linkedin: <a href="https://www.linkedin.com/in/nazare-emanuel-ioan-4298b5149/" rel="noopener">https://www.linkedin.com/in/nazare-emanuel-ioan-4298b5149/</a></li></ul> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo desplegar una aplicación Node.js: Desde la configuración del servidor hasta el entorno de producción ]]>
                </title>
                <description>
                    <![CDATA[ En este tutorial, aprenderemos todo lo que necesitamos saber antes de implementar una aplicación Node en un servidor de producción. Comenzaremos alquilando un servidor en Digital Ocean. Luego configuraremos este servidor, nos conectaremos a él, instalaremos Nginx y lo configuraremos, extraeremos o crearemos nuestra aplicación Node y la ejecutaremos como ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-desplegar-una-aplicacion-node-js-desde-la-configuracion-del-servidor-hasta-el-entorno-de-produccion/</link>
                <guid isPermaLink="false">64460d852ef44808032faf6f</guid>
                
                    <category>
                        <![CDATA[ Node ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ CipherBoB ]]>
                </dc:creator>
                <pubDate>Mon, 01 May 2023 00:56:03 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/04/603a54d9a675540a22924662.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/deploy-nodejs-app-server-to-production/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Deploy a Node.js App – From Server Setup to Production</a>
      </p><p>En este tutorial, aprenderemos todo lo que necesitamos saber antes de implementar una aplicación Node en un servidor de producción.</p><p>Comenzaremos alquilando un servidor en Digital Ocean. Luego configuraremos este servidor, nos conectaremos a él, instalaremos Nginx y lo configuraremos, extraeremos o crearemos nuestra aplicación Node y la ejecutaremos como un proceso.</p><p>Como puedes ver, hay mucho que hacer y será un tutorial lleno de acción. Así que comencemos sin perder tiempo.</p><p>Debes tener algunos conocimientos básicos sobre cómo funciona la Terminal y cómo trabajar con Vi/Vim antes de comenzar. Si no estás familiarizado con los comandos básicos, te aconsejo que los leas un poco.</p><p>Ejecutaré los comandos en MacOS. Si quieres seguir este tutorial en Windows, puedes usar Powershell o algún otro emulador de Unix de tu elección.</p><p>Aunque usaré Node.js como plataforma de nuestra aplicación de ejemplo, la mayoría de los pasos son los mismos para cualquier aplicación web.</p><h2 id="-por-qu-digital-ocean"><strong>¿Por qué Digital Ocean?</strong></h2><p>Elijo Digital Ocean porque es barato y la interfaz es realmente fácil de usar, en comparación con AWS. Además, se incluye un crédito de $100 en el paquete de estudiante de GitHub para que no tengas que pagar nada durante un par de meses. Es ideal para implementar un curso o un proyecto de pasatiempos.</p><p>Tiene un concepto llamado Droplets, que es básicamente tu parte de un servidor. Puedes imaginar el servidor como un apartamento del que eres propietario o un apartamento alquilado.</p><p>Los droplets funcionan con la ayuda de máquinas virtuales que se ejecutan en el servidor. Entonces, un Droplet es tu máquina virtual en un servidor compartido. Dado que es una máquina virtual, su uso compartido de CPU y memoria se puede aumentar fácilmente, generalmente invirtiendo más dinero en tu proveedor.</p><h2 id="c-mo-crear-un-proyecto-de-digital-ocean"><strong>Cómo crear un proyecto de Digital Ocean</strong></h2><figure class="kg-card kg-image-card"><img src="https://erinc.io/wp-content/uploads/2021/02/image-3.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-3.png" width="600" height="400" loading="lazy"></figure><p>Supongo que ya te has registrado e iniciado sesión en Digital Ocean antes de continuar. Primero debemos crear un proyecto que contenga nuestros droplets. Hagamos clic en el botón de nuevo proyecto en el menú del lado izquierdo. Te pedirá que nombres tu proyecto.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://erinc.io/wp-content/uploads/2021/02/Screen-Shot-2021-02-22-at-13.35.06.png" class="kg-image" alt="This image has an empty alt attribute; its file name is Screen-Shot-2021-02-22-at-13.35.06.png" width="600" height="400" loading="lazy"></figure><p>Introduce el nombre que quieras. También te preguntará si quieres mover algún recurso, pero por ahora simplemente haz clic en Omitir; crearemos el droplet más tarde.</p><h2 id="c-mo-crear-un-droplet-en-digital-ocean"><strong>Cómo crear un droplet en Digital Ocean</strong></h2><p>Vamos a crear nuestro droplet haciendo clic en el botón Comenzar.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://erinc.io/wp-content/uploads/2021/02/image-4-1024x593.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-4-1024x593.png" width="600" height="400" loading="lazy"></figure><p>Después de hacer clic en el botón, nos pedirá que elijamos una imagen de VM (Máquina virtual).</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://erinc.io/wp-content/uploads/2021/02/Screen-Shot-2021-02-22-at-13.12.43-1024x567.png" class="kg-image" alt="This image has an empty alt attribute; its file name is Screen-Shot-2021-02-22-at-13.12.43-1024x567.png" width="600" height="400" loading="lazy"><figcaption>Elegir una imagen</figcaption></figure><p>En esta página, seleccionaré Ubuntu 20.04, ya que es la última versión de LTS en el momento en que escribo esta publicación. LTS significa "Soporte a largo plazo" (por sus siglas en inglés). Lo mejor es optar por la versión LTS para proyectos reales, porque el proveedor garantiza que será compatible y mantenido durante mucho tiempo. Esto significa que no tendrás problemas a largo plazo.</p><p>Elegí Ubuntu y te lo recomendaría, ya que es la distribución de Linux más utilizada. Esto significa que también es más fácil encontrar respuestas a tus dudas futuras.</p><p>También puedes optar por tener una CPU dedicada si la necesitas. Si estás construyendo tu propia startup o cualquier proyecto comercial, te recomendaría leer esta <a href="https://www.digitalocean.com/docs/droplets/resources/choose-plan/">publicación</a> que contiene instrucciones detalladas sobre cómo elegir la opción adecuada para ti.</p><p>Seguiré con la opción más barata en este caso.</p><p>Luego, deberás seleccionar una región del centro de datos. Debes elegir el que esté más cerca de ti para minimizar el retraso de la red.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://erinc.io/wp-content/uploads/2021/02/image-2-1024x519.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-2-1024x519.png" width="600" height="400" loading="lazy"><figcaption>Seleccionar un centro de datos</figcaption></figure><p>A continuación, seleccionemos Claves SSH como el Método de autenticación, ya que es mucho más seguro que la autenticación de contraseña básica.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://erinc.io/wp-content/uploads/2021/02/image-5-1024x459.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-5-1024x459.png" width="600" height="400" loading="lazy"><figcaption>Método de autenticación</figcaption></figure><p>Para conectarnos al servidor necesitamos generar una nueva clave SSH en nuestro propio dispositivo y agregarla a Digital Ocean.</p><h2 id="c-mo-generar-una-clave-ssh"><strong>Cómo generar una clave SSH</strong></h2><p>Generaré la clave en mi dispositivo macOS. Si estás utilizando Windows, puedes consultar <a href="https://phoenixnap.com/kb/generate-ssh-key-windows-10">este</a> artículo. Abre tu terminal y muévete a la carpeta ssh:</p><pre><code>cd ~/.ssh</code></pre><p>Luego crea tu clave SSH:</p><pre><code>ssh-keygen</code></pre><p>Si tu computadora dice que no conoce este comando, debes instalarlo a través de brew.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://erinc.io/wp-content/uploads/2021/02/image-7-1024x140.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-7-1024x140.png" width="600" height="400" loading="lazy"></figure><p>Te pedirá que asignes un nombre al archivo e ingreses una frase de contraseña. No ingreses un nombre, solo presiona enter y sigue con los valores predeterminados. Deberías tener estos archivos generados. He nombrado el mío digital-ocean-ssh en esta captura de pantalla, así que no te confundas con eso.</p><pre><code>❯ lsid_dsa      id_rsa      known_hosts</code></pre><p>Nuestra clave pública es el <code>id_dsa</code> y el <code>id_rsa</code> es nuestra clave privada. Si olvidas cuál es la privada, siempre puedes imprimir una de ellas para verla.</p><h2 id="c-mo-agregar-tu-clave-ssh-a-digital-ocean"><strong>Cómo agregar tu clave SSH a Digital Ocean</strong></h2><p>Ahora queremos copiar nuestra clave pública y subirla a Digital Ocean para que sepan qué clave usar en la autenticación.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://erinc.io/wp-content/uploads/2021/02/image-9-1024x149.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-9-1024x149.png" width="600" height="400" loading="lazy"></figure><p>Copia toda esta clave, incluida la parte ssh-rsa.</p><p>Haz clic en "Nueva clave SSH":</p><figure class="kg-card kg-image-card"><img src="https://erinc.io/wp-content/uploads/2021/02/image-10.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-10.png" width="600" height="400" loading="lazy"></figure><p>Pega la clave en el cuadro de texto que aparece después de hacer clic en el botón y deberías ver tu clave SSH.</p><figure class="kg-card kg-image-card"><img src="https://erinc.io/wp-content/uploads/2021/02/image-11.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-11.png" width="600" height="400" loading="lazy"></figure><h2 id="c-mo-conectarse-al-servidor"><strong>Cómo conectarse al servidor</strong></h2><p>Usaremos la terminal para conectarnos a nuestro servidor con SSH. Si quieres también puedes echar un vistazo a Termius para obtener una buena interfaz.</p><p>Ejecuta este comando en tu terminal después de reemplazar IP_ADDRESS con la dirección IP de tu servidor (puedes buscarla desde el panel de Digital Ocean).</p><pre><code>ssh root@IP_ADDRESS</code></pre><p>Si todo va bien, ahora deberías estar en la terminal del servidor. Nos hemos conectado con éxito al servidor. Si hay algún error, puedes depurarlo ejecutando el comando con la opción "-v" o "-vv" para obtener aún más detalle.</p><h2 id="c-mo-configurar-el-servidor"><strong>Cómo configurar el servidor</strong></h2><p>Necesitamos hacer una configuración inicial antes de implementar la aplicación Node en el servidor.</p><h3 id="actualizar-el-software"><strong>Actualizar el software</strong></h3><p>Queremos actualizar el software del servidor para asegurarnos de que estamos usando las últimas versiones.</p><p>Muchos servidores son vulnerables a los ataques porque utilizan versiones anteriores de software con vulnerabilidades conocidas. Los atacantes pueden buscar las vulnerabilidades en ese software e intentar explotarlas para obtener acceso a tu servidor.</p><p>Puedes actualizar el software de Ubuntu usando el comando <strong><strong>"apt update"</strong></strong> .</p><pre><code>apt updateHit:1 https://repos.insights.digitalocean.com/apt/do-agent main InReleaseGet:2 http://mirrors.digitalocean.com/ubuntu focal InRelease [265 kB]      Hit:3 http://mirrors.digitalocean.com/ubuntu focal-updates InRelease                Get:4 http://security.ubuntu.com/ubuntu focal-security InRelease [109 kB]Hit:5 http://mirrors.digitalocean.com/ubuntu focal-backports InReleaseFetched 374 kB in 1s (662 kB/s)                          Reading package lists... DoneBuilding dependency tree       Reading state information... Done96 packages can be upgraded. Run 'apt list --upgradable' to see them.</code></pre><p>Si lees el mensaje, dice que "se pueden actualizar 96 paquetes". Hemos instalado los nuevos paquetes de software, pero aún no hemos actualizado nuestro software a esas versiones.</p><p>Para hacer eso, ejecutemos otro comando:</p><pre><code>apt upgrade</code></pre><p>Escribe 'y' cuando se te solicite y actualizarás el software.</p><h3 id="crear-un-usuario"><strong>Crear un usuario</strong></h3><p>Nos hemos conectado al servidor como el usuario root (el usuario con mayores privilegios). Ser root es peligroso y puede exponernos a vulnerabilidades.</p><p>Por lo tanto, debemos crear un nuevo usuario y no ejecutar comandos como root. Reemplaza <code>$username</code>con un nombre de usuario de tu elección.</p><pre><code>whoamiroot</code></pre><pre><code>adduser $username</code></pre><p>Es necesario introducir una contraseña para el usuario. Después de ese punto, hará un montón de preguntas, así que sigue avanzando hasta que terminen las indicaciones.</p><p>Se ha creado el nuevo usuario, pero también debemos agregar este nuevo usuario al grupo "sudo" para que podamos realizar cualquier acción que necesitemos.</p><pre><code>usermod -aG sudo $USERNAME</code></pre><p>Agregamos grupo con la opción <code>-aG</code> (agregar grupo), y agregamos el nombre del grupo <code>sudo</code>a nuestro nombre de usuario.</p><p>Todavía somos root, así que cambiemos nuestro usuario al usuario recién creado, usando el comando <code>su</code> (cambiar de usuario).</p><pre><code>su $USERNAME</code></pre><p>Después de este punto, si ejecutas el comando <strong><strong><code>whoami</code></strong></strong>, deberías ver tu nombre de usuario. Puedes confirmar la existencia del grupo sudo ejecutando este comando:</p><pre><code>sudo cat /var/log/auth.log</code></pre><p>Solo los superusuarios pueden ver este archivo y el sistema operativo te pedirá tu contraseña de usuario después de ejecutar este comando.</p><h3 id="copia-la-clave-ssh"><strong>Copia la clave SSH</strong></h3><p>Hemos creado correctamente el usuario, pero aún no hemos habilitado el inicio de sesión SSH para este nuevo usuario.</p><p>Por lo tanto, tenemos que copiar la clave pública que creamos previamente en nuestro ordenador local y pegarla en la carpeta SSH de este usuario para que SSH pueda saber qué clave debe usar para autenticar a nuestro nuevo usuario.</p><pre><code>mkdir -p ~/.ssh</code></pre><p>El argumento <code>-p</code> crea el directorio si no existe.</p><pre><code>vi ~/.ssh/authorized_keys</code></pre><p>Usaremos vi o vim para crear un archivo y llamarlo <strong><strong><code>authorized_keys</code></strong></strong>.</p><p>Copia tu clave pública (archivo `id_dsa`) y luego presiona "i" para entrar en el modo de inserción. Luego simplemente pégalo en este archivo con CMD + V (En Mac, si usas PC -&gt; CTRL + V).</p><p>Presiona esc para salir del modo de inserción, escribe <strong><strong>:wq</strong></strong> para guardar y salir.</p><p>Si tienes algún problema con el uso de Vim-Vi, puedes consultar <a href="https://www.freecodecamp.org/news/how-not-to-be-afraid-of-vim-anymore-ec0b7264b0ae/">uno de los muchos tutoriales</a> que explican cómo usarlo.</p><h3 id="conectarse-al-servidor-con-el-nuevo-usuario"><strong>Conectarse al servidor con el nuevo usuario</strong></h3><p>Ahora deberíamos poder conectarnos al servidor sin ningún problema usando ssh. Puedes usar este comando para conectarte, solo recuerda insertar tu nombre de usuario ($USERNAME) y dirección ip (<code>IP_ADDRESS</code>).</p><pre><code>ssh $USERNAME@IP_ADDRESS</code></pre><p>Si tienes algún problema en este punto, simplemente debes eliminar el droplet y comenzar de nuevo. No toma mucho tiempo comenzar de nuevo, pero la depuración de problemas del servidor puede ser difícil.</p><h3 id="c-mo-deshabilitar-el-inicio-de-sesi-n-con-root"><strong>Cómo deshabilitar el inicio de sesión con root</strong></h3><p>Es una buena práctica deshabilitar el inicio de sesión de root como medida de seguridad, así que hagámoslo ahora.</p><p>Puede ser útil cambiar el permiso del archivo por si acaso para que no tengamos problemas con los permisos en el futuro.</p><pre><code>chmod 644 ~/.ssh/authorized_keys</code></pre><p>Ahora abramos nuestro archivo <code>sshd_config</code>:</p><pre><code>sudo vi /etc/ssh/sshd_config</code></pre><p>Encuentra esta línea y cambia el sí por el no de la misma manera que lo hicimos antes con vi.</p><pre><code>PermitRootLogin no</code></pre><p>Guardar y salir de vi.</p><h2 id="c-mo-instalar-node-js-y-git"><strong>Cómo instalar Node.js y Git</strong></h2><p>Ya podemos continuar e instalar Node.js y Git:</p><pre><code>sudo apt install nodejs npm</code></pre><pre><code>sudo apt install git</code></pre><p>Ahora estamos listos para crear una aplicación Node y ejecutarla. Puedes extraer tu proyecto de Node de Github o crear una aplicación de Node aquí para probar si funciona.</p><p>Ves a un directorio de tu elección y crea un archivo <strong><strong>"app.js"</strong></strong> :</p><pre><code>sudo vi app.js</code></pre><p>Puedes pegar el siguiente fragmento en tu archivo <strong><strong>app.js</strong></strong> :</p><pre><code>const express = require('express');const app = express();const port = 3000;app.get('/', (req, res) =&gt; {        res.send('Hola Mundo');});app.listen(port, () =&gt; console.log(`¡Aplicación de ejemplo escuchando en el puerto ${port}!`));</code></pre><p>Ahora podemos ejecutarlo con el comando:</p><pre><code>node app.js</code></pre><p>Deberías ver "¡Aplicación de ejemplo escuchando en el puerto 3000!" en tu terminal.</p><p>Podemos confirmar que está funcionando enviando una solicitud a nuestro servidor:</p><pre><code>GET http://IP_ADDRESS:3000/</code></pre><p>Envía esta solicitud desde un cliente HTTP como Postman o tu navegador y deberías ver el mensaje "Hola Mundo".</p><p>En este punto, deberías notar que algo no está bien: Los usuarios regulares no saben cómo enviar solicitudes al puerto 3000.</p><p>Deberíamos redirigir las solicitudes que llegan a nuestro servidor web desde nuestra IP al puerto 3000. Esto lo podemos lograr con la ayuda de Nginx.</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://erinc.io/wp-content/uploads/2021/02/image-16.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-16.png" width="600" height="400" loading="lazy"></figure><h2 id="c-mo-instalar-y-configurar-nginx"><strong>Cómo instalar y configurar Nginx</strong></h2><p>Usaremos Nginx como proxy inverso para redirigir las solicitudes a nuestra aplicación Node.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://erinc.io/wp-content/uploads/2021/02/image-14-1024x531.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-14-1024x531.png" width="600" height="400" loading="lazy"><figcaption>Nginx como proxy inverso</figcaption></figure><p>Instalamos Nginx:</p><pre><code>sudo apt install nginx</code></pre><p>Inicia el servicio Nginx:</p><pre><code>sudo service nginx start</code></pre><p>Podemos probar para ver si funciona enviando una solicitud a la dirección IP de nuestro servidor desde el navegador. Escribe la dirección IP de tu servidor en tu navegador y deberías ver esto:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://erinc.io/wp-content/uploads/2021/02/image-15-1024x231.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-15-1024x231.png" width="600" height="400" loading="lazy"></figure><p>Es importante saber que Nginx sirve desde <strong><strong>"/var/www/html"</strong></strong> de forma predeterminada y también puedes encontrar este archivo HTML en ese directorio.</p><p>También te aconsejo que crees una carpeta en "/var/www", llámala app y mueve tu aplicación Node a esa carpeta para que sea fácil de encontrar.</p><h3 id="c-mo-configurar-el-proxy-inverso-de-nginx"><strong>Cómo configurar el proxy inverso de Nginx</strong></h3><p>Editaremos el archivo de configuración de Nginx para configurar un proxy inverso:</p><pre><code>sudo vi /etc/nginx/sites-available/default</code></pre><p>En este archivo, debes encontrar la ubicación / block y cambiarla de la siguiente manera:</p><pre><code>location / {                # First attempt to serve request as file, then                # as directory, then fall back to displaying a 404.                proxy_pass http://127.0.0.1:3000/;        }</code></pre><p>La directiva<code>proxy_pass</code> envía la solicitud a un puerto específico. Damos el puerto en el que se ejecuta nuestra aplicación Node.</p><p>Reiniciamos Nginx para que los cambios surtan efecto:</p><pre><code>sudo service nginx reload</code></pre><p>Después de este paso, deberíamos poder ver el mensaje cuando enviamos una solicitud a nuestro servidor. ¡Felicidades, hemos completado la cantidad mínima de pasos para implementar una aplicación Node!</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://erinc.io/wp-content/uploads/2021/02/Screen-Shot-2021-02-24-at-01.10.33-1024x67.png" class="kg-image" alt="This image has an empty alt attribute; its file name is Screen-Shot-2021-02-24-at-01.10.33-1024x67.png" width="600" height="400" loading="lazy"></figure><p>Pero aún así te aconsejo que completes el siguiente paso también, ya que creo que es bastante importante.</p><p>Si no puedes ver el mensaje de hola mundo, puedes verificar si tu aplicación y Nginx se están ejecutando y reiniciarlos.</p><h2 id="c-mo-ejecutar-tu-aplicaci-n-como-un-proceso"><strong>Cómo ejecutar tu aplicación como un proceso</strong></h2><p>No queremos iniciar nuestra aplicación manualmente cada vez que algo salga mal y nuestra aplicación falle. Queremos que se reinicie solo. Además, cada vez que se inicia el servidor, nuestra aplicación también debería iniciarse.</p><p>Para que esto suceda, podemos usar PM2. Instalemos PM2 y configuremos.</p><pre><code>sudo npm i -g pm2</code></pre><p>Estamos instalando pm2 globalmente usando la opción "-g" para que sea accesible desde todas las carpetas.</p><pre><code>pm2 start app.js</code></pre><p>Esto asegura que la aplicación se reinicie si se cierra debido a un error.</p><p>Guardemos la lista de procesos actual.</p><pre><code>pm2 save</code></pre><p>También necesitamos convertirlo en un demonio que se ejecute cada vez que se inicie el sistema:</p><pre><code>pm2 startup systemd</code></pre><figure class="kg-card kg-image-card kg-width-wide"><img src="https://erinc.io/wp-content/uploads/2021/02/image-17.png" class="kg-image" alt="This image has an empty alt attribute; its file name is image-17.png" width="600" height="400" loading="lazy"></figure><p>Como recordatorio, en este tutorial estoy usando los comandos para Ubuntu. Si estás utilizando cualquier otra distribución de Linux, debes reemplazar <code>systemd</code> en este comando.</p><p>Podemos confirmar que el servicio se reinicia reiniciando el servidor y enviando una solicitud sin ejecutar app.js a mano:</p><pre><code>sudo reboot</code></pre><p>Después de enviar una solicitud como lo hicimos anteriormente, deberías poder ver el mensaje de hola mundo.</p><h2 id="conclusi-n"><strong>Conclusión</strong></h2><p>En este tutorial, comenzamos desde cero, alquilamos un servidor, nos conectamos y lo configuramos de manera que sirve nuestra aplicación Node.js desde el puerto 80.</p><p>Si has seguido y has podido completar todos los pasos, ¡felicidades! Puedes estar orgulloso de ti mismo, ya que este tema no es de lo más fácil :). Espero que hayas aprendido mucho. Gracias por tu tiempo.</p><p>Planeo explorar más este tema conectando el servidor a un nombre de dominio y luego conectándolo a CircleCI para una integración continua. También revisaré los pasos necesarios para preparar la producción de tu aplicación Node.js/React. Sin embargo, esta publicación ya se había hecho lo suficientemente larga, por lo que esos temas están reservados para otra publicación :)</p><p>Si te ha gustado la lectura y quieres estar informado de mis futuras publicaciones, puedes suscribirte a mi <a href="https://erinc.io/">blog personal</a> . Puedes ver mis publicaciones anteriores allí si estás interesado en leer más. Suelo escribir sobre temas relacionados con el desarrollo web.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo usar TypeScript en aplicaciones React ]]>
                </title>
                <description>
                    <![CDATA[ ¡Hola a todos! Hace un tiempo escribí un artículo sobre TypeScript (en inglés [https://www.freecodecamp.org/news/an-introduction-to-typescript/]), explicando sus principales características y por qué es una buena idea usarlo en proyectos grandes. Hoy vamos a echar un vistazo rápido a cómo podemos usar TypeScript en una aplicación React, para que puedas tener una ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-usar-typescript-en-aplicaciones-react/</link>
                <guid isPermaLink="false">640264012154fe0736d631c9</guid>
                
                    <category>
                        <![CDATA[ typescript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ CipherBoB ]]>
                </dc:creator>
                <pubDate>Fri, 28 Apr 2023 00:54:03 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/04/bruno-martins-OhJmwB4XWLE-unsplash.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/using-typescript-in-react-apps/#intro-to-typescript" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Use TypeScript in React Apps</a>
      </p><p>¡Hola a todos! Hace un tiempo escribí <a href="https://www.freecodecamp.org/news/an-introduction-to-typescript/">un artículo sobre TypeScript (en inglés</a>), explicando sus principales características y por qué es una buena idea usarlo en proyectos grandes.</p><p>Hoy vamos a echar un vistazo rápido a cómo podemos usar TypeScript en una aplicación React, para que puedas tener una idea de cómo se vería la implementación y cuáles son sus beneficios.</p><h2 id="tabla-de-contenido"><strong><strong><strong>Tabla de contenido</strong></strong></strong></h2><ul><li>Introducción a TypeScript</li><li><a href="#tipos-para-props">Tipos para Props</a></li><li><a href="#tipos-para-hooks">Tipos para Hooks</a></li><li><a href="#usestate">Tipos para el hook useState</a></li><li><a href="#tipos-para-el-hook-useref">Tipos para el hook useRef</a></li><li><a href="#finales">Consideraciones finales</a></li></ul><h2 id="introducci-n-a-typescript"><strong>Introducción a TypeScript</strong></h2><p>A estas alturas ya deberías saber que TypeScript es un superconjunto (superset) de JavaScript. Superset significa que agrega funciones además de lo que ofrece JavaScript.</p><p>TypeScript toma todas las funcionalidades y estructuras que proporciona JavaScript como lenguaje y le agrega algunas cosas. Lo principal que proporciona TypeScript es la escritura estática.</p><p>Cuando se trata de React, además de todo lo que podemos escribir en vanilla JS (como variables, parámetros de funciones y valores devueltos, etc.), podemos usar TypeScript principalmente para escribir dos cosas: props de componentes y hooks.</p><p>Una de las formas más sencillas de crear una aplicación React con TypeScript es usar <a href="https://create-react-app.dev/docs/adding-typescript/">CRA</a>, ejecutando <code>npx create-react-app my-app --template typescript</code>.</p><p>Si ya tienes una aplicación CRA creada, en la documentación tienes información sobre cómo instalar TypeScript además de eso. ;)</p><p>Para los ejemplos aquí vamos a usar CRA, ya que es agradable y simple. Pero ten en cuenta que la mayoría de los marcos de trabajo (frameworks) como <a href="https://nextjs.org/docs/basic-features/typescript">Next</a> , <a href="https://vitejs.dev/guide/features.html#typescript">Vite</a> y <a href="https://docs.astro.build/en/guides/typescript/">Astro</a> también brindan soporte para TypeScript.</p><p>Entonces, después de ejecutar el script de CRA, tendrás un proyecto que se parece a esto:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-299.png" class="kg-image" alt="image-299" width="600" height="400" loading="lazy"></figure><p>Como puedes ver, los archivos ahora tienen un nombre <code>.tsx</code> que es cómo el compilador de TypeScript identifica que usará TypeScript en ese archivo.</p><p>Y además, tenemos un <code>tsconfig.json</code> que es donde tenemos toda la configuración del compilador. Puedes aprender más sobre eso en <a href="https://www.freecodecamp.org/news/an-introduction-to-typescript/#typescriptscompiler">el artículo anterior que escribí</a> (en inglés).</p><p>Ahora vamos a crear un componente y ver cómo podemos usar TypeScript.</p><!--kg-card-begin: html--><h2 id="tipos-para-props">Tipos para Props</h2><!--kg-card-end: html--><p>Para este ejemplo, configuraremos un componente ficticio responsable de representar un número recibido como props y agregarlo a ese número cuando se haga clic en un botón.</p><p>El código JavaScript normal se vería así:</p><pre><code class="language-javascript">const DummyComponent = ({ number, setNumber }) =&gt; {

  return (
    &lt;&gt;
      &lt;div&gt;{number}&lt;/div&gt;

      &lt;button
        onClick={() =&gt; setNumber(prev =&gt; prev+1)}
      &gt;
        ADD
      &lt;/button&gt;
    &lt;/&gt;
  )

}

export default DummyComponent</code></pre><p>Y nuestra versión completamente codificada se verá así:</p><pre><code class="language-javascript">import React, { Dispatch, SetStateAction } from 'react'

interface DummyProps {
  number: number
  setNumber: Dispatch&lt;SetStateAction&lt;number&gt;&gt;
}

const DummyComponent:React.FC&lt;DummyProps&gt; = ({ number, setNumber }) =&gt; {

  return (
    &lt;&gt;
      &lt;div&gt;{number}&lt;/div&gt;

      &lt;button
        onClick={() =&gt; setNumber(prev =&gt; prev+1)}
      &gt;
        ADD
      &lt;/button&gt;
    &lt;/&gt;
  )

}

export default DummyComponent</code></pre><p>Puedes ver que junto al nombre del componente, hemos agregado dos puntos y <code>React.FC</code>. Básicamente, esto le dice al componente TypeScript que <code>DummyComponent</code>es un componente funcional de React. Eso en sí no hace mucho, pero ayuda con el intellisense de TypeScript.</p><p>Junto a eso declaramos <code>&lt;DummyProps&gt;</code>. Esto declara que el objeto props que recibirá este componente debe coincidir con la interfaz <code>DummyProps</code>.</p><p>Una interfaz es la forma en que TypeScript le otorga un tipo a un objeto. Básicamente, declaramos todas las propiedades que tendrá ese objeto, y el tipo para cada una de ellas.</p><p>Dado que este componente recibirá un estado que es un número y una función para actualizar ese estado, eso es exactamente lo que tenemos en nuestra interfaz:</p><pre><code class="language-javascript">interface DummyProps {
  number: number
  setNumber: Dispatch&lt;SetStateAction&lt;number&gt;&gt;
}</code></pre><p>Aquí puedes ver que para la función <code>setNumber</code> estamos usando este tipo: <code>Dispatch&lt;SetStateAction&gt;</code>. Este no es un tipo nativo de TypeScript, sino que lo proporciona React. Entonces tenemos que importarlo cada vez que lo usamos, así:<br><code>import React, { Dispatch, SetStateAction } from 'react'</code>.</p><p>¡Y eso es todo! Les has dado tipos a tus props. Lo bueno de esto es que cada vez que llames a ese componente, obtendrás información sobre los props que espera ese componente. Lo mismo que si intentas pasar un prop no declarado en la interfaz del componente o proporcionas un tipo incorrecto para un prop esperado.</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-300.png" class="kg-image" alt="image-300" width="600" height="400" loading="lazy"><figcaption>Intellisense en props esperados</figcaption></figure><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-301.png" class="kg-image" alt="image-301" width="600" height="400" loading="lazy"><figcaption>Error de props inesperado</figcaption></figure><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-302.png" class="kg-image" alt="image-302" width="600" height="400" loading="lazy"><figcaption>Tipo de prop incorrecto</figcaption></figure><p>Esto es lo que la gente quiere decir cuando dice que TypeScript autodocumenta su código. Con solo unas pocas líneas repetitivas, ahora puedes ver fácilmente qué espera y qué no espera cada componente. Esto es muy útil cuando se trabaja en proyectos grandes, con cientos de componentes que fueron escritos en su mayoría por otras personas. ;)</p><!--kg-card-begin: html--><h2 id="tipos-para-hooks">Tipos para hooks</h2><!--kg-card-end: html--><p>Cuando se trata de hooks, TypeScript se usa principalmente para dar tipo a los hooks <code>useState</code> y <code>useRef</code>. Veamos cómo funciona eso.</p><!--kg-card-begin: html--><h2 id="usestate">Tipos para el hook <code>UseState</code></h2><!--kg-card-end: html--><p>Así es cómo se ve <code>useState</code> sin tipos:</p><pre><code class="language-javascript">const [number, setNumber] = useState&lt;&gt;(0)</code></pre><p>Y con los tipos se ve así:</p><pre><code class="language-javascript">const [number, setNumber] = useState&lt;number&gt;(0)
</code></pre><p>Casi no hay necesidad de explicarlo, ¿verdad? Simplemente, declaramos el tipo del valor del estado de esta manera: <code>&lt;number&gt;</code>y eso es todo. Si alguna vez intentamos actualizar ese estado con un tipo de valor diferente, obtendremos un bonito mensaje de error rojo para evitar que nos disparemos en el pie. ;)</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-303.png" class="kg-image" alt="image-303" width="600" height="400" loading="lazy"><figcaption>Error de tipo incorrecto</figcaption></figure><p>Ten en cuenta que si quieres permitir que nuestro estado tenga diferentes tipos de valores, podemos declararlo así: <code>const [number, setNumber] = useState&lt;number | string&gt;(0)</code>.</p><p>Ahora podemos pasar un número O una cadena sin obtener errores.</p><!--kg-card-begin: html--><h2 id="tipos-para-el-hook-useref">Tipos para el hook <code>UseRef</code></h2><!--kg-card-end: html--><p><code>useRef</code> es un hook que se utiliza principalmente para hacer referencia a elementos DOM en React. Si quieres obtener más información sobre cómo funciona el hook, puedes leer <a href="https://www.freecodecamp.org/news/full-guide-to-react-hooks/#useRef-hook">esta guía (en inglés)</a> que escribí recientemente.</p><p>Para ver cómo podemos implementarlo con TypeScript, usaremos este ejemplo:</p><pre><code class="language-javascript">import React, { useEffect, useRef } from 'react'

const DummyComponent:React.FC = () =&gt; {

  const ref = useRef&lt;HTMLInputElement&gt;(null)

  useEffect(() =&gt; {
    if (ref.current) ref.current.focus()
  }, [])

  return (
      &lt;input type="text" ref={ref} /&gt;
  )

}

export default DummyComponent</code></pre><p>Como puedes ver, iniciamos la variable <code>ref</code> con <code>null</code> y declaramos su tipo como <code>HTMLInputElement</code>. Al usar el hook useRef y declarar su tipo, la variable se puede asignar a <code>null</code> o al tipo declarado.</p><p>Entonces tenemos un hook <code>useEffect</code> que enfoca el elemento si tiene una propiedad <code>current</code>. Y, por último, estamos devolviendo un elemento <code>input</code> y asignando la referencia que declaramos anteriormente: <code>ref={ref}</code>.</p><p>Lo bueno de escribir el hook <code>useRef</code> es que TypeScript evitará que intentemos realizar acciones o leer datos de tipos que no coinciden.</p><p>Por ejemplo, si declaramos el tipo <code>number</code> para la referencia, obtendríamos los siguientes errores:</p><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-364.png" class="kg-image" alt="image-364" width="600" height="400" loading="lazy"><figcaption>La propiedad focus no existe en el tipo number</figcaption></figure><figure class="kg-card kg-image-card kg-width-wide kg-card-hascaption"><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-365.png" class="kg-image" alt="image-365" width="600" height="400" loading="lazy"><figcaption>No se puede asignar una referencia number a un elemento HTML</figcaption></figure><p>Una vez más, esto es bueno porque evita errores tontos antes de tiempo y nos evita tener que depurar estas cosas más adelante. Especialmente cuando se trabaja con grandes bases de código en las que también trabajan muchas otras personas, TypeScript nos brinda un entorno más controlado y ordenado para trabajar.</p><!--kg-card-begin: html--><h2 id="finales">Consideraciones finales</h2><!--kg-card-end: html--><p>Bueno, como siempre, espero que hayáis disfrutado del artículo y aprendido algo nuevo.</p><p>Si queréis profundizar más en este tema, os recomiendo este vídeo (en inglés) de <a href="https://www.youtube.com/watch?v=ydkQlJhodio">Firebase</a> o este otro de <a href="https://www.youtube.com/watch?v=Z5iWr6Srsj8">Ben Awad</a>.<br></p><p>Si queréis, también podéis seguirme en <a href="https://www.linkedin.com/in/germancocca/">LinkedIn</a> o <a href="https://twitter.com/CoccaGerman">Twitter</a>. ¡Nos vemos en la próxima!</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2023/01/goodbye-farewell.gif" class="kg-image" alt="goodbye-farewell" width="600" height="400" loading="lazy"></figure> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ React.js vs. React Native: ¿Cuál es la diferencia? ]]>
                </title>
                <description>
                    <![CDATA[ ¿Son lo mismo React.js y React Native? Si eres nuevo en el mundo del desarrollo web y móvil, quizás te estés preguntando lo mismo. Como novato, es fácil asumir que React.js y React Native son lo mismo. Después de todo, ambos tienen "Reaccionar" como parte de su nombre. Aunque React.js ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/react-js-vs-react-native-cual-es-la-diferencia/</link>
                <guid isPermaLink="false">640221c72154fe0736d62c0e</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ CipherBoB ]]>
                </dc:creator>
                <pubDate>Wed, 08 Mar 2023 20:46:06 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/03/pexels-pixabay-209339.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/react-js-vs-react-native-whats-the-difference/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">React.js vs React Native – What's the Difference?</a>
      </p><p>¿Son lo mismo React.js y React Native?</p><p>Si eres nuevo en el mundo del desarrollo web y móvil, quizás te estés preguntando lo mismo.</p><p>Como novato, es fácil asumir que React.js y React Native son lo mismo. Después de todo, ambos tienen "Reaccionar" como parte de su nombre.</p><p>Aunque React.js y React Native tienen mucho en común, son diferentes entre sí. En este artículo, explicaré tanto React.js cómo React Native, luego enumeraré sus similitudes y diferencias. Al final de este artículo, tendrás un conocimiento claro de ambas herramientas y para qué tipo de aplicaciones se suelen usar.</p><p>Para tener una idea clara de la diferencia entre React.js y React Native, primero debemos sumergirnos en cómo se renderiza un sitio web en un navegador.</p><h2 id="c-mo-se-renderizan-o-representan-los-sitios-web-html-css-y-javascript"><strong>Cómo se renderizan o representan los sitios web: HTML, CSS y JavaScript</strong></h2><p>Cuando escribes la URL de un sitio web en la barra de direcciones de tu navegador y haces clic en Intro, el navegador solicita el sitio web y el servidor web envía un archivo HTML al navegador.</p><p>El archivo HTML contiene el contenido de la página web y los archivos vinculados, como imágenes, videos y hojas de estilo. El navegador web analiza el archivo HTML y crea un modelo de objeto de documento (DOM), que es una estructura similar a un árbol que contiene los elementos de la página (por ejemplo, botones, párrafos, enlaces, etc...).</p><p>El navegador inicia las solicitudes de los archivos vinculados y los descarga al ordenador. Luego analiza los archivos vinculados, como CSS y JavaScript, y aplica el estilo al contenido, haciéndolo más presentable para el usuario. Después de descargar todos los archivos, el navegador muestra el contenido en la pantalla.</p><p>El navegador también ejecuta cualquier código JavaScript para que la página sea interactiva. Por ejemplo, si el usuario completa la información incorrecta en un formulario, se puede usar JavaScript para insertar un elemento <code>&lt;div&gt;</code> en la página que muestre un mensaje de error al usuario.</p><p>Sin embargo, uno de los mayores problemas de insertar elementos en el DOM con JavaScript es que el código no es reutilizable. Por ejemplo, si deseas insertar el mismo botón en la página, pero con diferentes colores de fondo, debes crear el elemento dos veces en JavaScript:</p><pre><code>let blueBtn = document.createElement("button").style.backgroundColor("blue")
let redBtn = document.createElement("button").style.backgroundColor("red")

// Inserta en la página un botón azul y uno rojo</code></pre><p>Este es solo un ejemplo simple. Con interfaces de usuario complejas, puedes imaginar lo largas y confusas que pueden llegar a ser las cosas. React fue desarrollado para resolver este problema al hacer que el proceso de creación de aplicaciones web sea mucho más organizado e intuitivo.</p><h2 id="-qu-es-react-js"><strong>¿Qué es React.js?</strong></h2><p>Técnicamente hablando, ReactJS es una biblioteca front-end de código abierto JavaScript para crear interfaces de usuario o componentes de interfaz de usuario. En términos simples, esto significa que puedes usar React para crear todas las partes de un sitio web que el usuario puede ver y con las que puede interactuar en la ventana de su navegador.</p><p>Entonces, ¿Cuál es la diferencia entre usar JavaScript simple y React? Bueno, React hace que el proceso de diseño de la interfaz de usuario sea mucho más fácil. Te permite crear elementos que puedes reutilizar fácilmente en otras partes del sitio web o la aplicación.</p><p>Con JavaScript, tal y como mencioné anteriormente, deberás escribir el mismo código dos veces para crear el mismo botón con diferentes colores, lo que podría generar complejidad en proyectos grandes.</p><p>La arquitectura de componentes de React resuelve este problema de manera brillante. Con React, defines una sola pieza de la interfaz de usuario, digamos un botón, como un componente.</p><pre><code>const Button (props) =&gt; {
	return (
    	&lt;div&gt;
        	&lt;button style={props.color}&gt;Submit&lt;/button&gt;
        &lt;/div&gt;
    )
}</code></pre><p>El componente en este caso es una función que devuelve una sintaxis similar a HTML llamada JSX, que define la presentación y el aspecto del componente en el navegador web.</p><p>Ahora, digamos que quieres usar el mismo botón (pero con diferentes colores) en varios lugares de tu sitio web. En lugar de crear cada botón desde cero con diferentes propiedades de color (como lo harías con JavaScript), con React, simplemente usas el mismo elemento <code>&lt;Button&gt;</code> y en <code>props</code> pasas un color diferente a cada uno de ellos creando variaciones del mismo botón.</p><pre><code>&lt;Button color="red" /&gt;
&lt;Button color="blue" /&gt;
&lt;Button color="green" /&gt;</code></pre><p>Este método hace todo simple y lo mantiene organizado, que es toda la esencia de la biblioteca React.js.</p><p>Otro beneficio de usar React para el desarrollo de UI es la separación de preocupaciones. Esto significa que los datos utilizados en un componente existen por separado de la lógica, que existe por separado de la capa de vista.</p><p>Aquí hay un ejemplo:</p><pre><code>const Button (props) =&gt; {
	// datos de los componentes
    const [btnText, setBtnText] = useState("Submit")
    
    // lógica de los componentes
    function onClick() {
    	setBtnText("Submitted!")
    }
    
	return (
    	// vista de los componentes
    	&lt;div&gt;
        	&lt;button style={props.color}&gt;{btnText}&lt;/button&gt;
        &lt;/div&gt;
    )
}</code></pre><p>Como puedes ver aquí, el estado, la lógica y la presentación de un componente están separados entre sí, lo que hace que los componentes de React UI sean más fáciles de entender y componer.</p><p>Para concluir, React es una biblioteca de JavaScript diseñada para simplificar el proceso de creación de la interfaz de las aplicaciones web.</p><h2 id="-qu-es-react-native"><strong>¿Qué es React Native?</strong></h2><p>Aquí están las principales diferencias entre ReactJS y React Native:</p><ul><li>React JS se utiliza para crear la interfaz de usuario de las aplicaciones web (es decir, aplicaciones que se ejecutan en un navegador web)</li><li>React Native se utiliza para crear aplicaciones que se ejecutan en dispositivos iOS y Android (es decir, aplicaciones móviles multiplataformas)</li><li>React usa HTML, CSS y JavaScript para crear interfaces de usuario interactivas. React Native, por otro lado, utiliza componentes de interfaz de usuario nativos y APIs para crear aplicaciones móviles.</li></ul><p>Tanto React JS como React Native comparten la misma sintaxis. React Native se creó como una forma para que los desarrolladores creasen aplicaciones móviles multiplataformas utilizando su conocimiento existente de herramientas de desarrollo web como HTML, CSS, JavaScript y la biblioteca principal de React.</p><p>De hecho, algunas de las bibliotecas que se usan comúnmente junto con React para desarrollar aplicaciones web también tienen una versión móvil para crear aplicaciones en React Native, por ejemplo, Axios, Bootstrap CSS y Tailwind CSS.</p><p>Estas son las cosas que React DOM y React Native tienen en común:</p><ol><li>Ambos usan la misma biblioteca principal de React.</li><li>Ambos utilizan la misma arquitectura basada en componentes, lo que significa que los desarrolladores pueden dividir sus aplicaciones en piezas más pequeñas y manejables.</li><li>Ambos usan JavaScript como lenguaje de programación y JSX como lenguaje de plantillas.</li><li>Tanto React DOM como React Native usan DOM virtuales para representar sus aplicaciones.</li><li>Tanto React DOM como React Native también usan las mismas técnicas y componentes de estilo, aunque React Native es un poco diferente.</li><li>Ambos utilizan Chrome DevTools para depurar aplicaciones.</li><li>Utilizan las mismas APIs de JavaScript.</li><li>Ambos fueron desarrollados en Meta. React fue desarrollado por un ingeniero de software llamado Jordan Walke, mientras que React Native nació de una hackathon.</li></ol><h2 id="conclusi-n"><strong>Conclusión</strong></h2><p>Este artículo exploró las diferencias entre React DOM y React Native, dos herramientas populares de JavaScript. React DOM se usa principalmente para el desarrollo web, mientras que React Native se usa para el desarrollo móvil.</p><p>React DOM usa HTML, CSS y JavaScript para el diseño y el estilo, y permite a los desarrolladores crear interfaces de usuario interactivas. React Native, por otro lado, utiliza componentes de interfaz de usuario nativos y APIs para crear aplicaciones móviles multiplataforma.</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo crear una aplicación de calculadora usando React Native: un tutorial paso a paso ]]>
                </title>
                <description>
                    <![CDATA[ Una aplicación de calculadora es una aplicación simple que siempre está disponible en todos los dispositivos Android, iOS y de escritorio. En este artículo, crearemos una aplicación de calculadora utilizando React Native y Expo. Entonces, ¿por qué estamos usando estas herramientas? React Native es un marco basado en JavaScript que ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-crear-una-aplicacion-de-calculadora-usando-reac-native-tutorial-paso-a-paso/</link>
                <guid isPermaLink="false">63fe37582154fe0736d61f38</guid>
                
                    <category>
                        <![CDATA[ react native ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ CipherBoB ]]>
                </dc:creator>
                <pubDate>Wed, 08 Mar 2023 16:31:02 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/03/banner---how-to-build-calculator-app-using-react-native-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/how-to-build-a-calculator-app-using-react-native-a-step-by-step-tutorial/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Build a Calculator App Using React Native – A Step-by-Step Tutorial</a>
      </p><p>Una aplicación de calculadora es una aplicación simple que siempre está disponible en todos los dispositivos Android, iOS y de escritorio.</p><p>En este artículo, crearemos una aplicación de calculadora utilizando React Native y Expo. Entonces, ¿por qué estamos usando estas herramientas?</p><p>React Native es un marco basado en JavaScript que se puede usar para desarrollar aplicaciones móviles en dos sistemas operativos al mismo tiempo: Android e iOS. React Native fue lanzado por primera vez en 2015 por Facebook y es de código abierto.</p><p>Puedes encontrar más información sobre React Native <a href="https://reactnative.dev/docs/getting-started" rel="noopener">aquí</a>.</p><p>Expo es un conjunto de herramientas, bibliotecas y servicios que puede usar para simplificar su código React Native. Entonces puede ejecutar aplicaciones React Native en el emulador Expo.</p><p>Puedes encontrar más información sobre Expo <a href="https://expo.dev/" rel="noopener">aquí</a>.</p><p>Antes de comenzar a crear una aplicación de calculadora, primero deberás instalar Node.js, React Native y Expo en tu ordenador.</p><h3 id="requisitos-previos"><strong>Requisitos previos</strong></h3><ol><li>Instala Node.js: Puedes ver cómo instalarlo <a href="https://nodejs.org/en/download/" rel="noopener">aquí</a>.</li><li>Instala React Native: Puedes ver la documentación de instalación <a href="https://reactnative.dev/docs/environment-setup" rel="noopener">aquí</a>.</li><li>Instala Expo: Puedes ver la documentación de instalación <a href="https://reactnative.dev/docs/environment-setup" rel="noopener">aquí</a>.</li></ol><h2 id="paso-1-crear-un-nuevo-proyecto"><strong>Paso 1: Crear un nuevo proyecto</strong></h2><p>El primer paso es crear un nuevo proyecto. Usa Expo CLI para crear la base de código React Native con el siguiente comando:</p><pre><code class="language-bash">$ expo init calculator-app</code></pre><p>Entonces tendrás la opción de iniciar el proyecto que desees. Aquí elegimos la opción en blanco y usamos JavaScript como se muestra a continuació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/01/image-349.png" class="kg-image" alt="image-349" width="600" height="400" loading="lazy"><figcaption>choose template expo project</figcaption></figure><p>Después de eso, el proceso continuará descargando todas las dependencias.</p><h2 id="paso-2-crear-el-componente-de-bot-n"><strong>Paso 2: Crear el componente de botón</strong></h2><p>Cuando desarrolles aplicaciones con React Native, asegúrate de dividir los componentes de la interfaz de usuario en componentes más pequeños para que el código que crees se pueda reutilizar.</p><p>Primero, crea una nueva carpeta llamada "<strong><strong>componentes</strong></strong>" para almacenar el código de tu componente. El primer componente que crearemos es un botón, así que crea un nuevo archivo llamado <strong><strong>Button.js</strong></strong>. Aquí está el código fuente para el componente Botón:</p><pre><code class="language-javascript">import { Dimensions, StyleSheet, Text, TouchableOpacity } from "react-native";

export default ({ onPress, text, size, theme }) =&gt; {
  const buttonStyles = [styles.button];
  const textStyles = [styles.text];

  if (size === "double") {
    buttonStyles.push(styles.buttonDouble);
  }

  if (theme === "secondary") {
    buttonStyles.push(styles.buttonSecondary);
    textStyles.push(styles.textSecondary);
  } else if (theme === "accent") {
    buttonStyles.push(styles.buttonAccent);
  }

  return (
    &lt;TouchableOpacity onPress={onPress} style={buttonStyles}&gt;
      &lt;Text style={textStyles}&gt;{text}&lt;/Text&gt;
    &lt;/TouchableOpacity&gt;
  );
};</code></pre><p>Explicación del código:</p><ul><li>En la línea 3, hay cuatro propiedades que necesitamos para hacer este componente Botón: onPress, texto, tamaño y tema.</li><li>Cada una de las propiedades tiene una función como onPress para manejar acciones en los botones.</li><li>El componente de botón que creamos tiene 2 tipos de temas, secundarios y de acento, y 1 tamaño, doble.</li><li>El componente de botón usa el componente React Native predeterminado, TouchableOpacity.</li></ul><p>Después de crear el código del componente, no olvides agregar el estilo para este componente de botón. Aquí está el código para el estilo del componente:</p><pre><code class="language-javascript">// set dimmenstion
const screen = Dimensions.get("window");
const buttonWidth = screen.width / 4;

const styles = StyleSheet.create({
  button: {
    backgroundColor: "#333333",
    flex: 1,
    height: Math.floor(buttonWidth - 10),
    alignItems: "center",
    justifyContent: "center",
    borderRadius: Math.floor(buttonWidth),
    margin: 5,
  },
  text: {
    color: "#fff",
    fontSize: 24,
  },
  textSecondary: {
    color: "#060606",
  },
  buttonDouble: {
    width: screen.width / 2 - 10,
    flex: 0,
    alignItems: "flex-start",
    paddingLeft: 40,
  },
  buttonSecondary: {
    backgroundColor: "#a6a6a6",
  },
  buttonAccent: {
    backgroundColor: "#ffc107",
  },
});
</code></pre><p>Entonces, el código completo de nuestro componente de botón es el siguiente:</p><pre><code class="language-javascript">import { Dimensions, StyleSheet, Text, TouchableOpacity } from "react-native";

export default ({ onPress, text, size, theme }) =&gt; {
  const buttonStyles = [styles.button];
  const textStyles = [styles.text];

  if (size === "double") {
    buttonStyles.push(styles.buttonDouble);
  }

  if (theme === "secondary") {
    buttonStyles.push(styles.buttonSecondary);
    textStyles.push(styles.textSecondary);
  } else if (theme === "accent") {
    buttonStyles.push(styles.buttonAccent);
  }

  return (
    &lt;TouchableOpacity onPress={onPress} style={buttonStyles}&gt;
      &lt;Text style={textStyles}&gt;{text}&lt;/Text&gt;
    &lt;/TouchableOpacity&gt;
  );
};

// set dimmenstion
const screen = Dimensions.get("window");
const buttonWidth = screen.width / 4;

const styles = StyleSheet.create({
  button: {
    backgroundColor: "#333333",
    flex: 1,
    height: Math.floor(buttonWidth - 10),
    alignItems: "center",
    justifyContent: "center",
    borderRadius: Math.floor(buttonWidth),
    margin: 5,
  },
  text: {
    color: "#fff",
    fontSize: 24,
  },
  textSecondary: {
    color: "#060606",
  },
  buttonDouble: {
    width: screen.width / 2 - 10,
    flex: 0,
    alignItems: "flex-start",
    paddingLeft: 40,
  },
  buttonSecondary: {
    backgroundColor: "#a6a6a6",
  },
  buttonAccent: {
    backgroundColor: "#ffc107",
  },
});
</code></pre><h2 id="paso-3-crear-el-componente-de-fila"><strong>Paso 3: Crear el componente de fila</strong></h2><p>El siguiente componente que crearemos es un componente Fila. Este componente es útil para crear filas cuando queremos procesar diseños.</p><p>Aquí está el código para el componente Fila y su código de estilo:</p><pre><code class="language-javascript">import { StyleSheet, View } from "react-native";

const Row = ({ children }) =&gt; {
  return &lt;View style={styles.container}&gt;{children}&lt;/View&gt;;
};

// create styles of Row
const styles = StyleSheet.create({
  container: {
    flexDirection: "row",
  },
});

export default Row;
</code></pre><p>Esto es lo que está pasando:</p><ul><li>En el componente de fila, hay 1 propiedad que necesitamos: Niños.</li><li>El componente de fila usa el componente de vista predeterminado de React Native.</li><li>flexDirection: "fila" en este estilo se usa para hacer que el diseño sea una fila.</li></ul><h2 id="paso-4-crear-la-l-gica-de-la-calculadora"><strong>Paso 4: Crear la lógica de la calculadora</strong></h2><p>Crea una nueva carpeta llamada útil y un nuevo archivo <strong><strong>calcula</strong>tor<strong>.js</strong></strong> . Aquí crearemos una función lógica en la aplicación de calculadora que implementaremos más adelante en el archivo <strong><strong>App.js. </strong></strong>Aquí está el código completo:</p><pre><code class="language-javascript">export const initialState = {
  currentValue: "0",
  operator: null,
  previousValue: null,
};

export const handleNumber = (value, state) =&gt; {
  if (state.currentValue === "0") {
    return { currentValue: `${value}` };
  }

  return {
    currentValue: `${state.currentValue}${value}`,
  };
};

const handleEqual = (state) =&gt; {
  const { currentValue, previousValue, operator } = state;

  const current = parseFloat(currentValue);
  const previous = parseFloat(previousValue);
  const resetState = { operator: null, previousValue: null };

  switch (operator) {
    case "+":
      return {
        currentValue: `${previous + current}`,
        ...resetState,
      };
    case "-":
      return {
        currentValue: `${previous - current}`,
        ...resetState,
      };
    case "*":
      return {
        currentValue: `${previous * current}`,
        ...resetState,
      };
    case "/":
      return {
        currentValue: `${previous / current}`,
        ...resetState,
      };

    default:
      return state;
  }
};

// calculator function
const calculator = (type, value, state) =&gt; {
  switch (type) {
    case "number":
      return handleNumber(value, state);
    case "clear":
      return initialState;
    case "posneg":
      return {
        currentValue: `${parseFloat(state.currentValue) * -1}`,
      };
    case "percentage":
      return {
        currentValue: `${parseFloat(state.currentValue) * 0.01}`,
      };
    case "operator":
      return {
        operator: value,
        previousValue: state.currentValue,
        currentValue: "0",
      };
    case "equal":
      return handleEqual(state);
    default:
      return state;
  }
};

export default calculator;
</code></pre><p>Y esto es lo que está pasando:</p><ul><li>initialState se usa para dar el valor predeterminado a nuestra aplicación de calculadora.</li><li>La función handleNumber sirve para devolver el valor de la calculadora y tiene 2 propiedades: valor y estado.</li><li>El identificador de función Equal sirve para procesar el valor establecido de cada operador matemático y devuelve su valor.</li><li>La calculadora de funciones válida cada operador dado. Por ejemplo, si el número llama a la función handleNumber, si está claro, devolverá el valor de estado predeterminado de initiaState, y así sucesivamente.</li></ul><h2 id="paso-5-refactorizar-el-archivo-app-js"><strong>Paso 5: Refactorizar el archivo App.js</strong></h2><p>Una vez que hemos creado todos los componentes y el proceso lógico, el siguiente paso es realizar ajustes en el código del archivo App.js. Aquí está el código completo:</p><pre><code class="language-javascript">import React, { Component } from "react";
import { SafeAreaView, StyleSheet, Text, View } from "react-native";
import Button from "./components/Button";
import Row from "./components/Row";
import calculator, { initialState } from "./util/calculator";

// create class component of App
export default class App extends Component {
  state = initialState;

  // handle tap method
  HandleTap = (type, value) =&gt; {
    this.setState((state) =&gt; calculator(type, value, state));
  };

  // render method
  render() {
    return (
      &lt;View style={styles.container}&gt;
        {/* Status bae here */}
        &lt;SafeAreaView&gt;
          &lt;Text style={styles.value}&gt;
            {parseFloat(this.state.currentValue).toLocaleString()}
          &lt;/Text&gt;

          {/* Do create componentRow */}
          &lt;Row&gt;
            &lt;Button
              text="C"
              theme="secondary"
              onPress={() =&gt; this.HandleTap("clear")}
            /&gt;

            &lt;Button
              text="+/-"
              theme="secondary"
              onPress={() =&gt; this.HandleTap("posneg")}
            /&gt;

            &lt;Button
              text="%"
              theme="secondary"
              onPress={() =&gt; this.HandleTap("percentage")}
            /&gt;

            &lt;Button
              text="/"
              theme="accent"
              onPress={() =&gt; this.HandleTap("operator", "/")}
            /&gt;
          &lt;/Row&gt;

          {/* Number */}
          &lt;Row&gt;
            &lt;Button text="7" onPress={() =&gt; this.HandleTap("number", 7)} /&gt;
            &lt;Button text="8" onPress={() =&gt; this.HandleTap("number", 8)} /&gt;
            &lt;Button text="9" onPress={() =&gt; this.HandleTap("number", 9)} /&gt;
            &lt;Button
              text="X"
              theme="accent"
              onPress={() =&gt; this.HandleTap("operator", "*")}
            /&gt;
          &lt;/Row&gt;

          &lt;Row&gt;
            &lt;Button text="5" onPress={() =&gt; this.HandleTap("number", 5)} /&gt;
            &lt;Button text="6" onPress={() =&gt; this.HandleTap("number", 6)} /&gt;
            &lt;Button text="7" onPress={() =&gt; this.HandleTap("number", 7)} /&gt;
            &lt;Button
              text="-"
              theme="accent"
              onPress={() =&gt; this.HandleTap("operator", "-")}
            /&gt;
          &lt;/Row&gt;

          &lt;Row&gt;
            &lt;Button text="1" onPress={() =&gt; this.HandleTap("number", 1)} /&gt;
            &lt;Button text="2" onPress={() =&gt; this.HandleTap("number", 2)} /&gt;
            &lt;Button text="3" onPress={() =&gt; this.HandleTap("number", 3)} /&gt;
            &lt;Button
              text="+"
              theme="accent"
              onPress={() =&gt; this.HandleTap("operator", "+")}
            /&gt;
          &lt;/Row&gt;

          &lt;Row&gt;
            &lt;Button text="0" onPress={() =&gt; this.HandleTap("number", 0)} /&gt;
            &lt;Button text="." onPress={() =&gt; this.HandleTap("number", ".")} /&gt;
            &lt;Button
              text="="
              theme="primary"
              onPress={() =&gt; this.HandleTap("equal", "=")}
            /&gt;
          &lt;/Row&gt;
        &lt;/SafeAreaView&gt;
      &lt;/View&gt;
    );
  }
}

// create styles of app
const styles = StyleSheet.create({
  container: {
    flex: 1,
    backgroundColor: "#202020",
    justifyContent: "flex-end",
  },
  value: {
    color: "#fff",
    fontSize: 42,
    textAlign: "right",
    marginRight: 20,
    marginBottom: 10,
  },
});
</code></pre><p>Algunas notas rápidas:</p><ul><li>handleTap es una función que creamos que tiene como objetivo proporcionar valores de estado y llamar a utils/calculator.</li><li>Aquí llamamos a dos componentes, Botón y Fila, para diseñar la apariencia de la calculadora, como sus números, operaciones matemáticas y el proceso de cálculo.</li></ul><h2 id="paso-6-ejecuta-la-aplicaci-n"><strong>Paso 6: Ejecuta la aplicación</strong></h2><p>En este paso intentaremos ejecutar la aplicación de calculadora en el dispositivo o podemos usar un emulador. Aquí uso el simulador de iPhone de MacOS. Ejecuta el siguiente comando para ejecutar el programa:</p><pre><code class="language-bash">$ yarn ios</code></pre><p>El proceso en ejecución aquí usa Expo como se muestra a continuación:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-350.png" class="kg-image" alt="image-350" width="600" height="400" loading="lazy"></figure><p>Si el proceso de compilación está completo, entonces la pantalla de la aplicación de calculadora que programamos será así:</p><figure class="kg-card kg-image-card kg-width-wide"><img src="https://www.freecodecamp.org/news/content/images/2023/01/image-351.png" class="kg-image" alt="image-351" width="600" height="400" loading="lazy"></figure><h2 id="conclusi-n"><strong>Conclusión</strong></h2><p>Eso es suficiente para este artículo. Aprendiste sobre estilo, componentes, propiedades y estados en React Native y creaste una aplicación de calculadora funcional.</p><p>Si necesitas el código fuente completo, puedes visitar mi repositorio de GitHub aquí: <a href="https://github.com/bangadam/calculator-app" rel="nofollow noopener noopener">https://github.com/bangadam/calculator-app</a></p><h3 id="-gracias-por-leer-"><strong>¡Gracias por leer!</strong></h3><p>¡Disponible para un nuevo proyecto! Hablemos.<br>Correo electrónico: <a href="mailto:bangadam.dev@gmail.com" rel="noopener ugc nofollow">bangadam.dev@gmail.com</a><br>Linkedin: <a href="https://www.linkedin.com/in/bangadam/" rel="noopener ugc nofollow noopener noopener">https://www.linkedin.com/in/bangadam</a></p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Repasa estas 50 preguntas para superar una entrevista de programación en Java ]]>
                </title>
                <description>
                    <![CDATA[ Una lista con preguntas frecuentes de Java en entrevistas de trabajo para programadores. ¡Hola todos! En los últimos años, he estado compartiendo muchas preguntas [http://javarevisited.blogspot.sg/2015/10/133-java-interview-questions-answers-from-last-5-years.html]  y debates sobre entrevistas de Java individualmente. Muchos de mis lectores me han pedido que las reúna para poder tenerlas en un mismo lugar. ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/repasa-estas-50-preguntas-para-superar-una-entrevista-de-programacion-en-java/</link>
                <guid isPermaLink="false">63f9f2e02154fe0736d61486</guid>
                
                    <category>
                        <![CDATA[ java ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ CipherBoB ]]>
                </dc:creator>
                <pubDate>Wed, 08 Mar 2023 15:24:05 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2023/02/1_s73cLB7vYz05f-aw_QAgFw--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/review-these-50-questions-to-crack-your-java-programming-interview-69d03d746b7f/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">https://www.freecodecamp.org/news/review-these-50-questions-to-crack-your-java-programming-interview-69d03d746b7f/</a>
      </p><p>Una lista con preguntas frecuentes de Java en entrevistas de trabajo para programadores.</p><p>¡Hola todos! En los últimos años, he estado compartiendo muchas <a href="http://javarevisited.blogspot.sg/2015/10/133-java-interview-questions-answers-from-last-5-years.html" rel="noopener">preguntas</a> y debates sobre entrevistas de Java individualmente. Muchos de mis lectores me han pedido que las reúna para poder tenerlas en un mismo lugar. Este post es el resultado de ello.</p><p>Este artículo contiene más de <strong><strong>50 preguntas </strong>de<strong> entrevista</strong>s<strong> de Java</strong></strong> que cubren todos los temas importantes, como los fundamentos de Core Java, <a href="https://javarevisited.blogspot.com/2011/11/collection-interview-questions-answers.html" rel="noopener">Java Collection Framework</a> , <a href="https://javarevisited.blogspot.com/2014/07/top-50-java-multithreading-interview-questions-answers.html#axzz5ghebTpxm" rel="noopener">Java Multithreading and Concurrency</a> , <a href="https://javarevisited.blogspot.com/2014/08/socket-programming-networking-interview-questions-answers-Java.html" rel="noopener">Java IO</a> , <a href="https://javarevisited.blogspot.com/2012/12/top-10-jdbc-interview-questions-answers.html" rel="noopener">JDBC</a> , <a href="http://www.java67.com/2016/08/10-jvm-options-for-java-production-application.html" rel="noopener">JVM Internals</a> , <a href="http://www.java67.com/2018/06/data-structure-and-algorithm-interview-questions-programmers.html" rel="noopener">Problemas de codificación</a> , <a href="http://www.java67.com/2015/12/top-30-oops-concept-interview-questions-answers-java.html" rel="noopener">Programación orientada a objetos</a> , etc.</p><p>Las preguntas también están extraídas de varias entrevistas y no son, en modo alguno, muy difíciles. Es posible que ya las hayas visto en tu teléfono o en la ronda de entrevistas cara a cara.</p><p>Las preguntas también son muy útiles para repasar temas importantes como hilos o subprocesos múltiples y colecciones. También he compartido algunos <em><em>recursos útiles para seguir aprendiendo y mejorando,</em></em> como <a href="https://click.linksynergy.com/fs-bin/click?id=JVFxdTr9V80&amp;subid=0&amp;offerid=323058.1&amp;type=10&amp;tmpid=14538&amp;RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fjava-the-complete-java-developer-course%2F" rel="noopener"><strong><strong>The Complete Java MasterClass</strong></strong></a> para repasar y llenar los vacíos en tus habilidades de Java.</p><p>Entonces... ¿Qué estamos esperando? Aquí está la lista de algunas de las preguntas de Java más frecuentes en entrevistas para desarrolladores de Java principiantes y experimentados.</p><h2 id="m-s-de-50-preguntas-de-entrevista-de-java-para-programadores-experimentados-de-2-a-3-a-os">Más de 50 preguntas de entrevista de Java para programadores experimentados de 2 a 3 años</h2><p>Pues... sin perder más tiempo, aquí está mi lista de algunas <a href="http://www.java67.com/2018/03/top-50-core-java-interview-questions.html" rel="noopener">preguntas de entrevista de Core Java</a> más frecuentes para programadores principiantes. Esta lista se enfoca en principiantes y desarrolladores menos experimentados, con 2 o 3 años de experiencia en Java.</p><h3 id="1-c-mo-consigue-java-la-independencia-de-la-plataforma-respuesta-">1) ¿Cómo consigue Java la independencia de la plataforma? (<a href="http://www.java67.com/2012/08/how-java-achieves-platform-independence.html" rel="noopener">respuesta</a>)</h3><p>pista: bytecode y Java Virtual Machine</p><h3 id="2-qu-es-el-classloaderen-java-respuesta-">2) ¿Qué es el ClassLoaderen Java? (<a href="http://javarevisited.blogspot.sg/2012/12/how-classloader-works-in-java.html#axzz59AWpr6cb" rel="noopener">respuesta</a>)</h3><p>pista: parte de JVM que carga bytecodes para clases. Puedes escribir el tuyo propio.</p><h3 id="3-escribir-un-programa-java-para-comprobar-si-un-n-mero-es-par-o-impar-respuesta-">3) ¿Escribir un programa Java para comprobar si un número es par o impar? (<a href="http://javarevisited.blogspot.sg/2013/04/how-to-check-if-number-is-even-or-odd.html#axzz59AWpr6cb" rel="noopener">respuesta</a>)</h3><p>pista: puedes usar el operador bit a bit, como AND bit a bit, recuerda que, los números pares tienen un cero al final en formato binario y los impares acaban en 1.</p><h3 id="4-diferencia-entre-arraylisty-hashseten-java-respuesta-">4) ¿Diferencia entre ArrayListy HashSeten Java? (<a href="http://www.java67.com/2012/07/difference-between-arraylist-hashset-in-java.html" rel="noopener">respuesta</a>)</h3><p>pista: todas las diferencias entre Listy Setson aplicables aquí, por ejemplo, ordenamiento, duplicados, búsqueda aleatoria, etc. Consulta <a href="https://pluralsight.pxf.io/c/1193463/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fjava-fundamentals-collections" rel="noopener">Fundamentos de Java: colecciones</a> de Richard Warburton para obtener más información sobre ArrayList, HashSet y otras colecciones importantes en Java.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/ueOwMAd5GBdw4blCOpEBpOdMOtcs-et6nPYA" class="kg-image" alt="ueOwMAd5GBdw4blCOpEBpOdMOtcs-et6nPYA" width="800" height="600" loading="lazy"></figure><h3 id="5-qu-es-el-bloqueo-de-doble-verificaci-n-en-singleton-respuesta-">5) ¿Qué es el bloqueo de doble verificación en Singleton? (<a href="http://www.java67.com/2016/04/why-double-checked-locking-was-broken-before-java5.html" rel="noopener">respuesta</a>)</h3><p>pista: verifica dos veces si las instancias están inicializadas o no, primero sin bloqueo y segundo con bloqueo.</p><h3 id="6-c-mo-se-crea-singleton-seguro-para-subprocesos-en-java-respuesta-">6) ¿Cómo se crea Singleton seguro para subprocesos en Java? (<a href="http://javarevisited.blogspot.sg/2012/12/how-to-create-thread-safe-singleton-in-java-example.html" rel="noopener">respuesta</a>)</h3><p>pista: de muchas maneras, como usar Enum o usar un patrón de bloqueo verificado dos veces así cómo usar una clase estática anidada.</p><h3 id="7-cu-ndo-usar-la-variable-vol-til-en-java-respuesta-">7) ¿Cuándo usar la variable volátil en Java? (<a href="http://www.java67.com/2012/08/what-is-volatile-variable-in-java-when.html" rel="noopener">respuesta</a>)</h3><p>pista: cuando necesitas indicar a la JVM que una variable puede ser modificada por múltiples subprocesos y dar una pista a la JVM para que no almacene en caché su valor.</p><h3 id="8-cu-ndo-usar-una-variable-transitoria-en-java-respuesta-">8) ¿Cuándo usar una variable transitoria en Java? (<a href="http://www.java67.com/2012/08/what-is-transient-variable-in-java.html" rel="noopener">respuesta</a>)</h3><p>pista: cuando quieras hacer que una variable no sea serializable en una clase que implemente la interfaz Serializable. En otras palabras, puedes usarla para una variable cuyo valor no quieras guardar. Consulta <a href="https://click.linksynergy.com/fs-bin/click?id=JVFxdTr9V80&amp;subid=0&amp;offerid=323058.1&amp;type=10&amp;tmpid=14538&amp;RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fjava-the-complete-java-developer-course%2F" rel="noopener">The Complete Java MasterClass</a> para obtener información sobre las variables transitorias en Java.</p><h3 id="9-diferencia-entre-la-variable-transitoria-y-vol-til-en-java-respuesta-">9) ¿Diferencia entre la variable transitoria y volátil en Java? &nbsp;(<a href="http://www.java67.com/2012/11/difference-between-transient-vs-volatile-modifier-variable-java.html" rel="noopener">respuesta</a>)</h3><p>pista: totalmente diferente, una se usa en el contexto de la serialización mientras que la otra se usa en concurrencia.</p><h3 id="10-diferencia-entre-serializable-y-externalizable-en-java-respuesta-">10) ¿Diferencia entre serializable y externalizable en Java? (<a href="http://www.java67.com/2012/10/difference-between-serializable-vs-externalizable-interface.html" rel="noopener">respuesta</a>)</h3><p>pista: externalizable da más control sobre el proceso de serialización.</p><h3 id="11-podemos-sobreescribir-un-m-todo-privado-en-java-respuesta-">11) ¿Podemos sobreescribir un método privado en Java? (<a href="http://www.java67.com/2013/08/can-we-override-private-method-in-java-inner-class.html" rel="noopener">respuesta</a>)</h3><p>pista: No, porque no está visible en la subclase, que es requisito principal para sobreescribir un método en Java.</p><p><strong><strong>12) ¿Diferencia entre <code>Hashtable</code></strong> <strong>y <code>HashMap</code>en Java? (<a href="http://javarevisited.blogspot.sg/2010/10/difference-between-hashmap-and.html#axzz53B6SD769" rel="noopener">respuesta</a>)</strong></strong><br>pista: varias pero la más importante es que <code>Hashtable</code> está sincronizada, mientras que <code>HashMap</code>no lo está. También es heredada y lenta en comparación con <code>HashMap</code>.</p><h3 id="13-diferencia-entre-list-y-set-en-java-respuesta-">13) ¿Diferencia entre List y Set en Java? (<a href="http://javarevisited.blogspot.sg/2012/04/difference-between-list-and-set-in-java.html#axzz53n9YK0Mb" rel="noopener">respuesta</a>)</h3><p>pista: Listestá ordenada y permite duplicacidad. Setestá desordenado y no permite elementos duplicados.</p><h3 id="14-diferencia-entre-arraylist-y-vectoren-java-respuesta-">14) Diferencia entre ArrayList y Vectoren Java (<a href="http://www.java67.com/2012/09/arraylist-vs-vector-in-java-interview.html" rel="noopener">respuesta</a>)</h3><p>pista: muchas, pero lo más importante es que ArrayList no está sincronizada y es rápida, mientras que Vector está sincronizada y es lenta. También es una clase heredada como Hashtable.</p><h3 id="15-diferencia-entre-hashtabley-concurrenthashmapen-java-respuesta-">15) ¿Diferencia entre Hashtabley ConcurrentHashMapen Java? (<a href="http://javarevisited.blogspot.sg/2011/04/difference-between-concurrenthashmap.html#axzz4qw7RoNvw" rel="noopener">respuesta</a>)</h3><p>pista: más escalable. Consulte <a href="https://pluralsight.pxf.io/c/1193463/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fjava-fundamentals-collections" rel="noopener">Fundamentos de Java: Colecciones</a> de Richard Warburton para obtener más información.</p><h3 id="16-c-mo-consigue-concurrenthashmap-escalabilidad-respuesta-">16) ¿Cómo consigue ConcurrentHashMap escalabilidad? (<a href="http://javarevisited.blogspot.sg/2017/08/top-10-java-concurrenthashmap-interview.html#axzz50U9xyqbo" rel="noopener">respuesta</a>)</h3><p>pista: dividiendo el mapa en segmentos y solo bloqueando durante la operación de escritura.</p><h3 id="17-qu-dos-m-todos-sobreescribir-para-que-objectse-use-como-keyen-hashmap-respuesta-">17) ¿Qué dos métodos sobreescribir para que Objectse use como Keyen HashMap? (<a href="http://www.java67.com/2013/06/how-get-method-of-hashmap-or-hashtable-works-internally.html" rel="noopener">respuesta</a>)</h3><p>pista: equals y hashcode</p><h3 id="18-diferencia-entre-esperar-y-dormir-en-java-respuesta-">18) ¿Diferencia entre esperar y dormir en Java? ( <a href="http://www.java67.com/2012/08/what-are-difference-between-wait-and.html" rel="noopener">respuesta</a> )</h3><p>pista: el método wait() libera el bloqueo o monitoriza, mientras que sleep() no lo hace.</p><h3 id="19-diferencia-entre-notify-y-notifyallen-java-respuesta-">19) ¿Diferencia entre notify y notifyAllen Java? (<a href="http://www.java67.com/2013/03/difference-between-wait-vs-notify-vs-notifyAll-java-thread.html" rel="noopener">respuesta</a>)</h3><p>pista: notify notifica que un subproceso aleatorio está esperando el bloqueo mientras notifyAll informa a todos los subprocesos que esperan un monitor. Si estás seguro de que solo hay un subproceso en espera, usa notify, sinó notifyAlles preferible. Consulta <a href="https://javaspecialists.teachable.com/p/threading-essentials/?product_id=539197&amp;coupon_code=SLACK100?affcode=92815_johrd7r8" rel="noopener">el minicurso de conceptos básicos de creación de subprocesos</a> impartido por el campeón de Java Heinz Kabutz para obtener más información sobre los conceptos básicos de creación de subprocesos.</p><h3 id="20-por-qu-anula-el-c-digo-hash-junto-con-equals-java-respuesta-">20) ¿Por qué anula el código hash, junto con equals()Java? (<a href="http://javarevisited.blogspot.sg/2015/01/why-override-equals-hashcode-or-tostring-java.html#axzz55oDxm8vv" rel="noopener">respuesta</a>)</h3><p>pista: para cumplir con la función de equals y hashcode, que se requiere si planeas almacenar un objeto en clases de colección, por ejemplo, HashMapo ArrayList.</p><h3 id="21-qu-representa-el-factor-de-carga-de-hashmap-respuesta-">21) ¿Qué representa el factor de carga de HashMap? (<a href="http://www.java67.com/2017/08/top-10-java-hashmap-interview-questions.html" rel="noopener">respuesta</a>)</h3><p>pista: el umbral que activa el cambio de tamaño HashMapes generalmente 0,75, lo que significa que HashMap cambia de tamaño si está lleno en un 75 por ciento.</p><h3 id="22-diferencia-entre-arraylist-y-linkedlisten-java-respuesta-">22) ¿Diferencia entre ArrayList y LinkedListen Java? (<a href="http://www.java67.com/2012/12/difference-between-arraylist-vs-LinkedList-java.html" rel="noopener">respuesta</a>)</h3><p>pista: la misma que una matriz y una lista vinculada, una permite la búsqueda aleatoria mientras que la otra no. La inserción y la eliminación son fáciles en la lista vinculada, pero la búsqueda es fácil en una matriz. Consulta <a href="https://pluralsight.pxf.io/c/1193463/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fjava-fundamentals-collections" rel="noopener"><strong><strong>Fundamentos de Java: Colecciones</strong></strong></a><strong><strong> ,</strong></strong> el curso de Richard Warburton sobre Pluralsight, para obtener más información sobre la estructura de datos de colección esencial en Java.</p><h3 id="23-diferencia-entre-countdownlatchy-cyclicbarrieren-java-respuesta-">23) ¿Diferencia entre CountDownLatchy CyclicBarrieren Java? (<a href="http://www.java67.com/2012/08/difference-between-countdownlatch-and-cyclicbarrier-java.html" rel="noopener">respuesta</a>)</h3><p>pista: puedes reutilizar CyclicBarrierdespués de que se rompa la barrera, pero no puedes reutilizar CountDownLatchdespués de que el conteo llegue a cero.</p><h3 id="24-cu-ndo-usar-runnable-vs-threaden-java-respuesta-">24) ¿Cuándo usar Runnable vs Threaden Java? (<a href="http://www.java67.com/2016/01/7-differences-between-extends-thread-vs-implements-Runnable-java.html" rel="noopener">respuesta</a>)</h3><p>pista: siempre</p><h3 id="25-cu-l-es-el-significado-de-que-enum-sea-seguro-para-tipos-en-java-respuesta-">25) ¿Cuál es el significado de que Enum sea seguro para tipos en Java? (<a href="http://www.java67.com/2014/04/what-java-developer-should-know-about-Enumeration-type-in-Java.html" rel="noopener">respuesta</a>)</h3><p>pista: significa que no se puede asignar una instancia de diferente tipo Enum a una variable Enum. por ejemplo, si tienes una variable como DiaDeLaSemana, entonces no puedes asignarle al día un valor desde una enumeración DiaDelMes.</p><h3 id="26-c-mo-funciona-autoboxing-of-integer-en-java-respuesta-">26) ¿Cómo funciona Autoboxing of Integer en Java? (<a href="http://javarevisited.blogspot.sg/2012/07/auto-boxing-and-unboxing-in-java-be.html#axzz59AWpr6cb" rel="noopener">respuesta</a>)</h3><p>pista: Usando el método valueOf() en Java.</p><h3 id="27-diferencia-entre-pathy-classpath-en-java-respuesta-">27) ¿Diferencia entre PATHy Classpath en Java? (<a href="http://www.java67.com/2012/08/what-is-path-and-classpath-in-java-difference.html" rel="noopener">respuesta</a>)</h3><p>pista: PATHlo utiliza el sistema operativo, mientras que Classpath lo utiliza JVM para localizar archivos binarios de Java, por ejemplo, archivos JAR o archivos de clase. Consulta <a href="https://pluralsight.pxf.io/c/1193463/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fjava-fundamentals-core-platform" rel="noopener">Fundamentos de Java: la plataforma principal</a> para obtener más información acerca de PATH, Classpath, y otras variables de entorno de Java.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/io-lPE67oMG1oBh204LvPm61t7kAcLFvp-B6" class="kg-image" alt="io-lPE67oMG1oBh204LvPm61t7kAcLFvp-B6" width="382" height="262" loading="lazy"></figure><h3 id="28-diferencia-entre-sobrecarga-y-anulaci-n-de-m-todos-en-java-respuesta-">28) ¿Diferencia entre sobrecarga y anulación de métodos en Java? (<a href="http://www.java67.com/2015/08/top-10-method-overloading-overriding-interview-questions-answers-java.html" rel="noopener">respuesta</a>)</h3><p>pista: la sobreescritura ocurre en la subclase mientras que la sobrecarga ocurre en la misma clase. Además, la sobreescritura es una actividad en tiempo de ejecución, mientras que la sobrecarga se resuelve en tiempo de compilación.</p><h3 id="29-c-mo-evitar-que-una-clase-se-subclasifique-en-java-respuesta-">29) ¿Cómo evitar que una clase se subclasifique en Java? (<a href="http://www.java67.com/2017/06/10-points-about-final-modifier-in-java.html" rel="noopener">respuesta</a>)</h3><p>pista: simplemente haciendo que tu constructor sea privado</p><h3 id="30-c-mo-restringir-una-clase-para-que-no-sea-utilizada-por-el-cliente-respuesta-">30) ¿Cómo restringir una clase para que no sea utilizada por el cliente? (<a href="http://javarevisited.blogspot.sg/2016/01/why-jpa-entity-or-hibernate-persistence-should-not-be-final-in-java.html" rel="noopener">respuesta</a>)</h3><p>pista: haciendo que el constructor sea privado o lanzando una excepción desde el constructor</p><h3 id="31-diferencia-entre-stringbuildery-stringbufferen-java-respuesta-">31) ¿Diferencia entre StringBuildery StringBufferen Java? (<a href="http://www.java67.com/2016/10/5-difference-between-stringbuffer.html" rel="noopener">respuesta</a>)</h3><p>pista: StringBuilderno está sincronizado mientras que StringBufferestá sincronizado.</p><h3 id="32-diferencia-entre-polimorfismo-y-herencia-en-java-respuesta-">32) ¿Diferencia entre polimorfismo y herencia en Java? (<a href="http://www.java67.com/2014/04/difference-between-polymorphism-and-Inheritance-java-oops.html" rel="noopener">respuesta</a>)</h3><p>pista: la herencia permite la reutilización del código y construye la relación entre clases, lo cual es requerido por el polimorfismo, que proporciona un comportamiento dinámico. Consulta <a href="https://pluralsight.pxf.io/c/1193463/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fjava-fundamentals-object-oriented-design" rel="noopener">Fundamentos de Java: diseño orientado a objetos</a> para obtener más información sobre las funciones de programación orientada a objetos.</p><h3 id="33-podemos-sobreescribir-un-m-todo-est-tico-en-java-respuesta-">33) ¿Podemos sobreescribir un método estático en Java? (<a href="http://www.java67.com/2012/08/can-we-override-static-method-in-java.html" rel="noopener">respuesta</a>)</h3><p>pista: No, porque la sobreescritura se resuelve en tiempo de ejecución mientras que la llamada al método estático se resuelve en tiempo de compilación.</p><h3 id="34-podemos-acceder-al-m-todo-privado-en-java-respuesta-">34) ¿Podemos acceder al método privado en Java? (<a href="http://www.java67.com/2012/08/can-we-override-private-method-in-java.html" rel="noopener">respuesta</a>)</h3><p>pista: sí, en la misma clase pero no fuera de la clase</p><h3 id="35-diferencia-entre-interfaz-y-clase-abstracta-en-java-respuesta-">35) ¿Diferencia entre interfaz y clase abstracta en Java? (<a href="http://www.java67.com/2017/08/difference-between-abstract-class-and-interface-in-java8.html" rel="noopener">respuesta</a>)</h3><p>pista: desde <a href="https://dzone.com/articles/5-courses-to-crack-java-certification-ocajp-1z0-80" rel="noopener">Java 8</a> , la diferencia es borrosa. Sin embargo, una clase Java aún puede implementar múltiples interfaces pero solo puede extender una clase.</p><h3 id="36-diferencia-entre-el-analizador-dom-y-sax-en-java-respuesta-">36) ¿Diferencia entre el analizador DOM y SAX en Java? (<a href="http://www.java67.com/2012/09/dom-vs-sax-parser-in-java-xml-parsing.html" rel="noopener">respuesta</a>)</h3><p>pista: DOM carga todo el archivo XML en la memoria mientras que SAX no lo hace. Es un analizador basado en eventos y se puede usar para analizar un archivo grande, DOM es rápido y es preferible para archivos pequeños.</p><h3 id="37-diferencia-entre-la-palabra-clave-throw-y-throws-en-java-respuesta-">37) ¿Diferencia entre la palabra clave throw y throws en Java? (<a href="http://www.java67.com/2012/10/difference-between-throw-vs-throws-in.html" rel="noopener">respuesta</a>)</h3><p>pista: throws declara qué excepción puede lanzar un método en caso de error, pero la palabra clave throw en realidad arroja una excepción. Consulta <a href="https://pluralsight.pxf.io/c/1193463/424552/7490?u=https%3A%2F%2Fwww.pluralsight.com%2Fcourses%2Fjava-fundamentals-exception-handling" rel="noopener">Conceptos básicos de Java: manejo de excepciones</a> para obtener más información sobre el manejo de excepciones en Java.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/QSqKD-b97Dr36kViV1eTdvqNVNgdZRp52D7n" class="kg-image" alt="QSqKD-b97Dr36kViV1eTdvqNVNgdZRp52D7n" width="718" height="316" loading="lazy"></figure><h3 id="38-diferencia-entre-iteradores-a-prueba-de-fallos-y-r-pidos-en-java-respuesta-">38) ¿Diferencia entre iteradores a prueba de fallos y rápidos en Java? (<a href="http://www.java67.com/2015/06/what-is-fail-safe-and-fail-fast-iterator-in-java.html" rel="noopener">respuesta</a>)</h3><p>pista: a prueba de fallos no arroja ConcurrentModificationException mientras que fail-fast lo hace cada vez que detecta un cambio externo en la colección subyacente mientras itera sobre ella.</p><h3 id="39-diferencia-entre-iterador-y-enumeraci-n-en-java-respuesta-">39) ¿Diferencia entre iterador y enumeración en Java? (<a href="http://javarevisited.blogspot.sg/2010/10/what-is-difference-between-enumeration.html#axzz59AWpr6cb" rel="noopener">respuesta</a>)</h3><p>pista: Iterator también proporciona la capacidad de eliminar un elemento mientras itera, sin embargo Enumeration no lo permite.</p><h3 id="40-qu-es-identityhashmap-en-java-respuesta-">40) ¿Qué es IdentityHashMap en Java? (<a href="http://www.java67.com/2016/09/difference-between-identityhashmap-weakhashmap-enummap-in-java.html" rel="noopener">respuesta</a>)</h3><p>pista: Un Map, que utiliza el operador de igualdad== para verificar la igualdad en lugar del método equals().</p><h3 id="41-qu-es-el-string-pool-en-java-respuesta-">41) ¿Qué es el String pool en Java? (<a href="http://javarevisited.blogspot.sg/2016/07/difference-in-string-pool-between-java6-java7.html#axzz4pGGwsyna" rel="noopener">respuesta</a>)</h3><p>pista: un grupo de String literales. Recuerda que se movió al heap desde el perm gen space en JDK 7.</p><h3 id="42-puede-una-clase-serializable-contener-un-campo-no-serializable-en-java-respuesta-">42) ¿Puede una clase Serializable contener un campo no serializable en Java? (<a href="http://javarevisited.blogspot.sg/2016/09/how-to-serialize-object-in-java-serialization-example.html" rel="noopener">respuesta</a>)</h3><p>pista: Sí, pero debe ser estático o transitorio.</p><h3 id="43-diferencia-entre-this-y-super-en-java-respuesta-">43) ¿Diferencia entre this y super en Java? (<a href="http://www.java67.com/2013/06/difference-between-this-and-super-keyword-java.html" rel="noopener">respuesta</a>)</h3><p>pista: this se refiere a la instancia actual, mientras que super se refiere a una instancia de la superclase.</p><h3 id="44-diferencia-entre-comparatory-comparableen-java-respuesta-">44) ¿Diferencia entre Comparatory Comparableen Java? (<a href="http://www.java67.com/2013/08/difference-between-comparator-and-comparable-in-java-interface-sorting.html" rel="noopener">respuesta</a>)</h3><p>pista: Comparatordefine el orden personalizado mientras Comparabledefine el orden natural de los objetos, por ejemplo, el orden alfabético para String. Consulta <a href="https://click.linksynergy.com/fs-bin/click?id=JVFxdTr9V80&amp;subid=0&amp;offerid=323058.1&amp;type=10&amp;tmpid=14538&amp;RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fjava-the-complete-java-developer-course%2F" rel="noopener">The Complete Java MasterClass</a> para obtener más información sobre la clasificación en Java.</p><figure class="kg-card kg-image-card"><img src="https://cdn-media-1.freecodecamp.org/images/DOCGFtdTMhjj3faRAiQ69ZSTxf2pffyroFfv" class="kg-image" alt="DOCGFtdTMhjj3faRAiQ69ZSTxf2pffyroFfv" width="800" height="437" loading="lazy"></figure><h3 id="45-diferencia-entre-java-util-date-y-java-sql-date-en-java-respuesta-">45) ¿Diferencia entre java.util.Date y java.sql.Date en Java? (<a href="http://javarevisited.blogspot.sg/2012/04/difference-between-javautildate-and.html" rel="noopener">respuesta</a>)</h3><p>pista: la primera contiene tanto la fecha como la hora, mientras que la segunda contiene sólo &nbsp;parte de la fecha.</p><h3 id="46-por-qu-los-m-todos-esperar-y-notificar-se-declaran-en-la-claseobject-en-java-respuesta-">46) ¿Por qué los métodos esperar y notificar se declaran en la claseObject en Java? (<a href="http://javarevisited.blogspot.sg/2012/02/why-wait-notify-and-notifyall-is.html" rel="noopener">respuesta</a>)</h3><p>pista: porque requieren un bloqueo que solo está disponible para un Object.</p><h3 id="47-por-qu-java-no-admite-herencias-m-ltiples-respuesta-">47) ¿Por qué Java no admite herencias múltiples? (<a href="http://javarevisited.blogspot.sg/2011/07/why-multiple-inheritances-are-not.html" rel="noopener">respuesta</a>)</h3><p>pista: No es compatible debido a una mala experiencia con C++, pero con Java 8, en cierto sentido sí lo es; sólo la herencia múltiple deType no son compatibles con Java ahora.</p><h3 id="48-diferencia-entre-excepci-n-marcada-y-no-marcada-en-java-respuesta-">48) ¿Diferencia entre Excepción marcada y no marcada en Java? (<a href="http://javarevisited.blogspot.sg/2011/12/checked-vs-unchecked-exception-in-java.html" rel="noopener">respuesta</a>)</h3><p>pista: en caso de ser checked, debes manejar la excepción usando el bloque catch, mientras que en caso de no ser checked, depende del programador; no dará error al compilar.</p><h3 id="49-diferencia-entre-error-y-excepci-n-en-java-respuesta-">49) ¿Diferencia entre error y excepción en Java? (<a href="http://www.java67.com/2012/12/difference-between-error-vs-exception.html" rel="noopener">respuesta</a>)</h3><p>pista: estoy cansado de escribir por favor comprueba la respuesta</p><h3 id="50-diferencia-entre-la-condici-n-de-race-y-el-deadlock-en-java-respuesta-">50) ¿Diferencia entre la condición de Race y el Deadlock en Java? (<a href="http://javarevisited.blogspot.sg/2012/02/what-is-race-condition-in.html#axzz59AbkWuk9" rel="noopener">respuesta</a>)</h3><p>pista: ambos son errores que ocurren en una aplicación concurrente, uno ocurre debido a la programación de hilos, threads o subprocesos mientras que el otro ocurre debido a una codificación deficiente. Consulta <a href="https://click.linksynergy.com/fs-bin/click?id=JVFxdTr9V80&amp;subid=0&amp;offerid=323058.1&amp;type=10&amp;tmpid=14538&amp;RD_PARM1=https%3A%2F%2Fwww.udemy.com%2Fmultithreading-and-parallel-computing-in-java%2F" rel="noopener">Multithreading and Parallel Computing in Java (Cómputo en paralelo y subprocesos múltiples en Java</a>) para obtener más información sobre Deadlocks, condiciones de Race y otros problemas de subprocesos múltiples (multithreading).</p><h2 id="notas-de-cierre">Notas de cierre</h2><p>Gracias, Llegaste al final del artículo… ¡Buena suerte con tu entrevista de programación! Ciertamente no será fácil, pero siguiendo esta hoja de ruta y esta guía, estarás un paso más cerca de convertirte en un <a href="https://hackernoon.com/10-free-courses-to-learn-docker-for-programmers-and-devops-engineers-7ff2781fd6e0" rel="noopener">ingeniero de DevOps</a> .</p><h4 id="recursos-adicionales-en-ingl-s-"><strong>Recursos adicionales (en inglés)</strong></h4><blockquote><strong><strong>P</strong>.D. <strong>—</strong></strong> si necesitas algunos recursos GRATUITOS para aprender Java, puedes consultar esta lista de <strong><strong><a href="http://www.java67.com/2018/08/top-10-free-java-courses-for-beginners-experienced-developers.html" rel="noopener">cursos gratuitos de Java</a></strong></strong> para comenzar tu preparación.<br><br><strong><strong>P</strong>.<strong>S</strong>.<strong>S</strong>. <strong>—</strong> </strong>no he proporcionado la respuesta a las preguntas de la entrevista compartidas en la imagen "¿Cuántos objetos String se crean en el código?" ¿Podrías adivinar y explicar?</blockquote> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo hacer la validación de entradas simple y limpia en tu app Express.js ]]>
                </title>
                <description>
                    <![CDATA[ > Este tutorial requiere conocimientos previos sobre el uso del framework express.js ¿Por qué necesitamos la validación en el lado del servidor?  * La validación en el lado del cliente no es suficiente y puede ser subvertida  * Mayor propensión a ataques de intermediario    [https://es.wikipedia.org/wiki/Ataque_de_intermediario]. ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-hacer-la-validacion-de-entradas-simple-y-limpia-en-tu-app-expressjs/</link>
                <guid isPermaLink="false">637e406b0211a808a5f3a0b4</guid>
                
                    <category>
                        <![CDATA[ JavaScript ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ CipherBoB ]]>
                </dc:creator>
                <pubDate>Wed, 30 Nov 2022 19:47:27 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2022/11/1-e0mCbx2PuNysG54g0B1gRg.jpeg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/how-to-make-input-validation-simple-and-clean-in-your-express-js-app-ea9b5ff5a8a7/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to make input validation simple and clean in your Express.js app</a>
      </p><blockquote>Este tutorial requiere conocimientos previos sobre el uso del framework express.js</blockquote><h4 id="-por-qu-necesitamos-la-validaci-n-en-el-lado-del-servidor">¿Por qué necesitamos la validación en el lado del servidor?</h4><ul><li>La validación en el lado del cliente no es suficiente y puede ser subvertida</li><li>Mayor propensión a <a href="https://es.wikipedia.org/wiki/Ataque_de_intermediario">ataques de intermediario</a>. El servidor nunca debe confiar en el lado del cliente</li><li>Un usuario puede desactivar la validación de JavaScript del lado del cliente y manipular los datos</li></ul><p>Si has creado aplicaciones web utilizando un framework Express o cualquier otro framework Node.js, la validación juega un papel crucial en cualquier aplicación web que requiera que valide la solicitud <code>body</code> <code>param</code> <code>query</code>.</p><p>Escribir tu propia función de middleware puede ser engorroso si</p><ul><li>Quieres avanzar rápido a la vez que mantienes la calidad del código o</li><li>Quieres evitar usar <code><strong>if</strong> (<strong>req</strong>.body.head)</code> o <code><strong>if</strong> (<strong>req</strong>.params.isCool)</code> en tu función del controlador principal donde defines la lógica de negocios</li></ul><p>En este tutorial, aprenderás cómo validar la entrada de datos en una aplicación Express.js utilizando un módulo popular y de código abierto llamado <a href="https://github.com/ctavan/express-validator" rel="noopener">express-validator</a>.</p><h3 id="introducci-n-a-express-validator">Introducción a express-validator</h3><p>La definición en Github dice:</p><blockquote>express-validator es un conjunto de middlewares <a href="http://expressjs.com/" rel="noopener">express.js</a> que envuelve el validador <a href="https://github.com/chriso/validator.js" rel="noopener">validator.js</a> &nbsp;y otras funciones de sanitización.</blockquote><p>El módulo implementa cinco importantes API’s:</p><ul><li>Check API</li><li>Filter API</li><li>Sanitization chain API</li><li>Validation chain API</li><li>Validation Result API</li></ul><p>Demos un vistazo a la creación de un usuario mediante una <code>route</code> básica sin ningún módulo de validación para crearlo: <code>/route/user.js</code></p><pre><code class="language-js">/**
* @api {post} /api/user Create user
* @apiName Create new user
* @apiPermission admin
* @apiGroup User
*
* @apiParam  {String} [userName] username
* @apiParam  {String} [email] Email
* @apiParam  {String} [phone] Phone number
* @apiParam  {String} [status] Status
*
* @apiSuccess (200) {Object} mixed `User` object
*/

router.post('/', userController.createUser)</code></pre><p>Ahora en el controlador de usuario <code>/controllers/user.js</code></p><pre><code class="language-js">const User = require('./models/user')

exports.createUser = (req, res, next) =&gt; {
  /** Aquí debe validar la entrada del usuario. 
    Sólo el Nombre del usuario y el email serán campos requeridos
 */
  
  const { userName, email, phone, status } = req.body
  if (userName &amp;&amp; email &amp;&amp;  isValidEmail(email)) { 
    
    // isValidEmail es una función personalizada que es necesario escribir desde cero o usar un módulo npm para validar el email 
    User.create({
      userName,
      email,
      phone,
      status,   
    })
    .then(user =&gt; res.json(user))
    .catch(next)
  }
}</code></pre><p>El código de arriba es solo un ejemplo básico de validación de campos personalizados.</p><p>Puedes implementar algunas validaciones en tu modelo de usuario usando Mongoose. Una buena práctica es asegurarse de que la validación ocurra antes que la lógica de negocios.</p><p><a href="https://github.com/ctavan/express-validator" rel="noopener">express-validator</a> se encargará de todas estas validaciones y también de la sanitización de las entradas</p><h4 id="instalaci-n"><strong>Instalación</strong></h4><pre><code class="language-bash">npm install --save express-validator</code></pre><p>Incluye <strong>módulo</strong> de tu archivo principal <code>server.js</code>:</p><pre><code class="language-js">const express = require('express')
const bodyParser = require('body-parser')
const expressValidator = require('express-validator')
const app = express()
const router = express.Router()

app.use(bodyParser.json())

app.use(expressValidator())

app.use('/api', router)</code></pre><p>El uso de <a href="https://github.com/ctavan/express-validator" rel="noopener">express-validator</a>. El archivo <code>/routes/user.js</code> quedaría así:</p><pre><code class="language-js">router.post(
  '/', 
  userController.validate('createUser'), 
  userController.createUser,
)</code></pre><p><code>userController.validate</code> es una función middleware que se explica a continuación. Acepta el nombre del <code>method</code> para el cual se usará la validación.</p><p>La función middleware &nbsp;<code>validate()</code> sería la siguiente en nuestro <code>/controllers/user.js</code>:</p><pre><code class="language-js">const { body } = require('express-validator/check')

exports.validate = (method) =&gt; {
  switch (method) {
    case 'createUser': {
     return [ 
        body('userName', 'userName doesn't exists').exists(),
        body('email', 'Invalid email').exists().isEmail(),
        body('phone').optional().isInt(),
        body('status').optional().isIn(['enabled', 'disabled'])
       ]   
    }
  }
}</code></pre><p>La función <code>body</code> sólo válida <code>req.body</code> y se le pasan dos argumentos. El primero es <code>property name</code>. Y el segundo es un mensaje personalizado <code>message</code> que se mostrará si la validación falla. Si no se proporciona un mensaje personalizado, mostrará un mensaje por defecto.</p><p>Como hemos podido ver, para un campo <code>required</code> usamos el método <code>.exists()</code> . Usamos <code>.optional()</code> para un campo <code>optional</code>. Igualmente, <code>isEmail()</code> &nbsp;e <code>isInt()</code> sirven para <code>email</code> e <code>integer</code>.</p><p>Si quieres definir una entrada que admita sólo ciertos valores, podemos usar <code>.isIn([])</code>. Esta función toma un <code>array</code> de valores, y si recibe otros valores lanza un error.</p><p>Por ejemplo, el campo status del código de arriba sólo puede tener un valor binario<code>enabled</code> o <code>disabled</code>. Si el usuario proporciona otro valor, la función lanza un error.</p><p>Dentro de <code>/controllers/user.js</code> añadimos una función <code><strong>createUser</strong></code> dónde describimos la lógica de negocios. Esta puede llamarse después de &nbsp;<code><strong>validate()</strong></code><strong> </strong>con el resultado de las validaciones.</p><pre><code class="language-js">const { validationResult } = require('express-validator/check');

exports.createUser = async (req, res, next) =&gt; {
   try {
      const errors = validationResult(req); // Encuentra los errores de validación en esta solicitud y los envuelve en un objeto resultante de una práctica función

      if (!errors.isEmpty()) {
        res.status(422).json({ errors: errors.array() });
        return;
      }

      const { userName, email, phone, status } = req.body
      
      const user = await User.create({

        userName,

        email,

        phone,

        status,   
      })

      res.json(user)
   } catch(err) {
     return next(err)
   }
}</code></pre><h3 id="si-te-preguntas-qu-es-validationresult-req-">Si te preguntas qué es validationResult(req)...</h3><p><strong>Esta función encuentra los errores de validación en la solicitud y los envuelve en un objeto</strong></p><p>Ahora, siempre que en la solicitud <code>req.body</code> se incluyan parámetros no válidos o falte el campo <code>userName</code>, el servidor responderá lo siguiente:</p><pre><code class="language-js">{
  "errors": [{
    "location": "body",
    "msg": "userName is required",
    "param": "userName"
  }]
}</code></pre><p>A su vez, si falla la validación de <code>userName</code> o <code>email</code> cada error devuelto por el método, <code>.array()</code> tendrá el siguiente formato por defecto:</p><pre><code class="language-js">{   
  "msg": "El mensaje de error",
   
  "param": "nombre del parámetro", 
  
  "value": "valor del parámetro",   
  // Location del parámetro que ha generado el error.   
  // Sus correspondientes body, query, params, cookies o headers.   
  "location": "body",    
  
 // nestedErrors sólo existe cuando se usa la función oneOf 
  "nestedErrors": [{ ... }] 
}</code></pre><p>Como hemos podido ver, este módulo nos ayuda con la mayor parte de las validaciones personalizadas, permitiéndonos mantener un código de calidad centrado principalmente en la lógica de negocios.</p><p>Esta ha sido una introducción a la validación de entradas usando el módulo <strong>express-validator</strong> y en la parte 2 de esta serie de artículos podrás ver cómo hacer una validación personalizada de una matriz de elementos y más</p><p><em>Artículo original en inglés publicado en </em><a href="https://101node.io/blog/how-to-validate-inputs-in-express-js-app/" rel="noopener"><em>101node.io</em></a><em> el 2 de septiembre del 2018.</em> &nbsp; </p> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
