<?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[ David Sabalete Rodriguez - 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[ David Sabalete Rodriguez - freeCodeCamp.org ]]>
            </title>
            <link>https://www.freecodecamp.org/espanol/news/</link>
        </image>
        <generator>Eleventy</generator>
        <lastBuildDate>Sat, 23 May 2026 19:21:58 +0000</lastBuildDate>
        <atom:link href="https://www.freecodecamp.org/espanol/news/author/david-sabalete-rodriguez/rss.xml" rel="self" type="application/rss+xml" />
        <ttl>60</ttl>
        
            <item>
                <title>
                    <![CDATA[ Cómo convertirte en profesional con React setState() en 10 minutos ]]>
                </title>
                <description>
                    <![CDATA[ Este artículo está dirigido a personas que ya han tenido su primer acercamiento a React, y que, como principiantes, tienen dudas sobre cómo funciona setState y cómo usarlo correctamente. También debería ayudar a los desarrolladores de nivel medio a superior a usar formas más limpias y abstractas de establecer el ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-convertirte-en-profesional-con-react-setstate-en-10-minutos/</link>
                <guid isPermaLink="false">635bae0a2b42f608ea5f02a6</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Sabalete Rodriguez ]]>
                </dc:creator>
                <pubDate>Wed, 30 Nov 2022 03:36:35 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2022/10/0-_agRQIzQvukx6TC7.jpg" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/get-pro-with-react-setstate-in-10-minutes-d38251d1c781/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to become a pro with React setState() in 10 minutes</a>
      </p><p>Este artículo está dirigido a personas que ya han tenido su primer acercamiento a React, y que, como principiantes, tienen dudas sobre cómo funciona <code>setState</code> y cómo usarlo correctamente. También debería ayudar a los desarrolladores de nivel medio a superior a usar formas más limpias y abstractas de establecer el estado, y hacer que las funciones de orden superior manejen y abstraigan el estado.</p><p>¡Solo lee y diviértete!</p><p>¡Así que toma una taza de café y sigue leyendo!</p><h3 id="conceptos-b-sicos-de-setstate-">Conceptos básicos de setState( )</h3><p>Los componentes de React le permiten dividir la interfaz de usuario (IU) en piezas independientes y reutilizables, para que pueda pensar en cada pieza de forma aislada.</p><p>Conceptualmente, los componentes son como funciones de JavaScript. Aceptan entradas arbitrarias (llamadas "propiedades" o "props") y devuelven elementos React que describen lo que debería aparecer en la pantalla.</p><p>Si necesita darle al usuario la oportunidad de ingresar algo o de alguna manera cambiar las variables que el componente recibe como propiedades, necesitará <code>setState</code>.</p><p>Ya sea que declare un Componente como una función o una clase, nunca debe modificar sus propios accesorios.</p><p>Todos los componentes de React deben actuar como funciones puras con respecto a sus propiedades. Esto significa funciones que nunca intentan cambiar sus entradas y siempre devuelven el mismo resultado para las mismas entradas.</p><p>Por supuesto, las interfaces de usuario de las aplicaciones son dinámicas y cambian con el tiempo. Por eso se creó <code>state</code>.</p><p><code>State</code> permite que los componentes de React cambien su salida con el tiempo en respuesta a las acciones del usuario, las respuestas de la red y cualquier otra cosa, sin violar esta regla.</p><p>Los Componentes definidos como clases tienen algunas características adicionales. El estado local es una función disponible solo para los Componentes de clase.</p><p><code>setState</code> es el método API proporcionado con la librería para que el usuario pueda definir y manipular el estado a lo largo del tiempo.</p><h3 id="tres-reglas-generales-al-usar-setstate-">Tres reglas generales al usar setState( )</h3><p><br>No modifiques el estado directamente</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/1.png" class="kg-image" alt="1" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/1.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/1.png 716w" width="716" height="580" loading="lazy"><figcaption>formas incorrectas y correctas de establecer el estado</figcaption></figure><h3 id="las-actualizaciones-de-estado-pueden-ser-asincr-nicas">Las actualizaciones de estado pueden ser asincrónicas</h3><p>React puede agrupar varias llamadas <code>setState()</code> en una sola actualización para mejorar el rendimiento.</p><p>Debido a que <strong><code>this.props </code></strong> y <code>this.state</code> pueden actualizarse de forma asíncrona, no debe confiar en sus valores para calcular el siguiente estado. &nbsp; &nbsp; </p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/2.png" class="kg-image" alt="2" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/2.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/2.png 800w" sizes="(min-width: 720px) 720px" width="800" height="496" loading="lazy"><figcaption>manipular el estado con un enfoque funcional</figcaption></figure><p>Siempre debe hacer este tipo de manipulación con un enfoque funcional, proporcionando el <code>state</code> y los <code>props</code> y devolviendo el nuevo <code>state</code> basado en el anterior.</p><h3 id="las-actualizaciones-de-estado-se-fusionan">Las actualizaciones de estado se fusionan</h3><p>Cuando llamas a <code>setState()</code>, React fusiona el objeto que proporcionas en el resto del <code>state</code> actual.</p><p>En el siguiente ejemplo, estamos actualizando la variable <code>dogNeedsVaccination</code> independientemente de las otras variables de <code>state</code>.</p><p>La fusión es superficial, por lo que <code>this.setState({ dogNeedsVaccination: true }) </code>deja intactas las otras variables, reemplazando solo el valor de <code>dogNeedsVaccination</code>.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/3.png" class="kg-image" alt="3" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/3.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/3.png 732w" sizes="(min-width: 720px) 720px" width="732" height="750" loading="lazy"></figure><h3 id="respeta-el-flujo-de-datos-y-evita-el-estado-al-m-ximo"><strong>Respeta el flujo de datos y evita el estado al máximo</strong></h3><p><strong>¡Los datos fluyen hacia abajo!</strong> Ni los componentes principales ni los secundarios pueden saber si un determinado componente tiene estado o no, y no debería importarles si se define como una función o una clase.</p><p>Es por eso que el <code>state</code> a menudo se llama local o encapsulado. No es accesible a ningún componente que no sea el que lo posee y lo configura.</p><p>Cuando estableces una propiedad de estado y lo usas en tu componente, estás interrumpiendo el flujo de las propiedades de renderizado. Si por alguna razón la propiead pasad a tu componente cambia en el componente padre, ¿el hijo no se volverá a renderizar automáticamente por arte de magia?</p><p>Veamos un ejemplo:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/4.png" class="kg-image" alt="4" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/4.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/4.png 800w" sizes="(min-width: 720px) 720px" width="800" height="1127" loading="lazy"></figure><p>Aquí tienes un Componente <code>Home</code> que está generando un número mágico cada 1000ms y poniéndolo en su propio <code>state</code>.</p><p>Después de eso, representa el número e invoca a tres Componentes <code>Child</code> (Hermanos) que recibirán el número mágico con el objetivo de mostrarlo usando tres enfoques diferentes:</p><h3 id="primer-enfoque">Primer enfoque</h3><p>El Componente <code>ChildOfHome</code> está respetando el flujo de cascada de props de React y, considerando que el objetivo es solo mostrar el número mágico, está renderizando los <code>props</code> recibidos directamente.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/5.png" class="kg-image" alt="5" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/5.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/5.png 796w" sizes="(min-width: 720px) 720px" width="796" height="648" loading="lazy"></figure><h3 id="segundo-enfoque">Segundo enfoque</h3><p>El Componente <code>ChildOfHomeBrother</code> recibe las <code>props</code> de su padre y, invocando <code>componentDidMount</code>, establece el número mágico en el <code>state</code>. Luego representa el <code>state.magicNumber</code>.</p><p>Este ejemplo no funcion porque <code>render()</code>no sabe que una <code>prop</code> ha cambiado, por lo que no activa la nueva representación del componente. Como el componente y no se vuelve a representar, no se invoca el <code>componentDidMount</code> y la pantalla no se actualiza.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/6.png" class="kg-image" alt="6" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/6.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/6.png 800w" sizes="(min-width: 720px) 720px" width="800" height="874" loading="lazy"></figure><h4 id="tercer-enfoque">Tercer enfoque</h4><p>Por lo general, cuando intentamos que funcione con el segundo enfoque, pensamos que falta algo. ¡En lugar de dar un paso atrás, seguimos agregando cosas al código para que funcione!</p><p>Entonces, en este tercer enfoque, agregamos <code>componentDidUpdate</code> para verificar si hay un cambio en <code>props</code> para activar la nueva representación del componente. Esto es innecesario y nos lleva a un código sucio. También trae consigo costos de rendimiento que se multiplicarán por la cantidad de veces que hagamos esto en una aplicación grande donde tenemos muchos componentes encadenados y efectos secundarios.</p><p>Esto es incorrecto a menos que necesite permitir que el usuario cambie el valor de prop recibido.</p><p>Si no necesita cambiar el valor de prop, siempre trate de mantener las cosas funcionando de acuerdo con el Flujo de React (Primer Enfoque).</p><p>Puede consultar una página web en funcionamiento con este ejamplo que he preparado para ti en &nbsp;<a href="https://freezing-transport.glitch.me/" rel="noopener">Glitch</a>. ¿Echa un vistazo y diviértete?</p><p>Consulta también el código en &nbsp;<code><strong>Home.js</strong></code> y &nbsp;<code><strong>HomeCodeCleaned.js</strong></code> &nbsp;(sin las cosas de HTML) en <a href="https://github.com/evedes/set-state-in-10-min">mi repositorio</a> sobre este artículo.</p><h3 id="c-mo-establecer-el-estado-con-setstate">Cómo establecer el estado con setState</h3><p>Entonces, llegados a este punto, ¡creo que es hora de ensuciarse las manos!</p><p>¡Juguemos un poco con <code>setState</code> y mejoremos eso! Solo sigue y toma otra taza de café!</p><p>Vamos a crear un pequeño formulario para actualizar los datos del usuario:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/7.png" class="kg-image" alt="7" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/7.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/7.png 800w" sizes="(min-width: 720px) 720px" width="800" height="451" loading="lazy"><figcaption>pequeño ejercicio con setState()</figcaption></figure><p>Aquí está el código para el ejemplo anterior:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/8.png" class="kg-image" alt="8" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/8.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/8.png 800w" sizes="(min-width: 720px) 720px" width="800" height="733" loading="lazy"><figcaption>Componente Home inicial</figcaption></figure><p>Estamos configurando el <code>state</code> como un objeto y no hay problema porque nuestro estado actual no depende de nuestro último estado.</p><p>¿Qué pasa si creamos un campo de formulario más para introducir y mostrar el Apellido (Last Name)?</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/9.png" class="kg-image" alt="9" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/9.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/9.png 800w" sizes="(min-width: 720px) 720px" width="800" height="491" loading="lazy"><figcaption>Característica Last Name</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/10.png" class="kg-image" alt="10" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/10.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/10.png 796w" sizes="(min-width: 720px) 720px" width="796" height="546" loading="lazy"><figcaption>handleFormChange abstraído</figcaption></figure><p>¡Bien! Hemos abstraído el método <code>handleFormChange</code> para poder manejar todos los campos de entrada y <code>setState</code>.</p><p>¿Qué pasa si agregamos un botón para marcar los datos como válidos o no válidos y un contador para saber cuántos cambios hemos hecho en el <code>state</code>?</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/11.png" class="kg-image" alt="11" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/11.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/11.png 800w" sizes="(min-width: 720px) 720px" width="800" height="741" loading="lazy"><figcaption>captura de pantalla que muestra los console.log del estado del componente</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/12.png" class="kg-image" alt="12" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/12.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/12.png 800w" sizes="(min-width: 720px) 720px" width="800" height="407" loading="lazy"><figcaption>handleFormChange actualizado con controladores de casillas de verificación y contadores</figcaption></figure><p>¡Sí! ¡Lo estamos petando! ¡Hemos abstraído muchas cosas!</p><p>Hmmm... Digamos que no quiero una casilla de verificación para controlar la variable, <code>isValid</code> sino un simple botón de alternancia.</p><p>También separemos el controlador de contador de este método. Funciona bien, pero en situaciones más complejas en las que React necesita cambios por lotes/grupos, no es una buena política confiar en la variable <code>this.state.counter</code> para agregar uno más. Este valor puede cambiar sin que te des cuenta.</p><p>Estamos usando una copia superficial del mismo en el instante en que se invoca la operación, y en ese momento determinado no sabes si su valor es el que esperabas o no.</p><p>¡Vamos a ponernos un poco funcionales!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/13.png" class="kg-image" alt="13" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/13.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/13.png 800w" sizes="(min-width: 720px) 720px" width="800" height="741" loading="lazy"><figcaption>captura de pantalla mostrando el Toggle Valid/Invalid y los console.log de la variable state.counter</figcaption></figure><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/14.png" class="kg-image" alt="14" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/14.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/14.png 796w" sizes="(min-width: 720px) 720px" width="796" height="1158" loading="lazy"><figcaption>separación de los controladores</figcaption></figure><p>Vale – Hemos perdido la abstracción porque hemos separado los controladores, ¡pero es por una buena razón!</p><p>Así que en este momento mantenemos <code>handleFormChange</code> pasando un objeto al método API <code>setState</code>. Pero los métodos <code>handleCounter</code> y <code>handleIsValid</code> ahora son funcionales y comienzan tomando el estado actual y luego, dependiendo de ese estado, cambiándolo al siguiente.</p><p>Esta es la forma correcta de cambiar el estado de las variables que dependen del estado anterior.</p><p>¿Qué pasa si queremos cambiar el estado de <code>console.log()</code> de los formularios de entrada <code>firstName</code> y <code>lastName</code> cada vez que ocurre un cambio? ¡Hagamos un intento!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/15.png" class="kg-image" alt="15" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/15.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/15.png 800w" sizes="(min-width: 720px) 720px" width="800" height="550" loading="lazy"><figcaption>método logFields()</figcaption></figure><p>¡Muy bien! Cada vez que se produce <code>handleFormChange</code> (lo que significa que se ha pulsado una nueva tecla), se invoca el método <code>logFields()</code> y se registra el estado actual en la consola.</p><p>Comprobemos la consola del navegador:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/16.png" class="kg-image" alt="16" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/16.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/16.png 800w" sizes="(min-width: 720px) 720px" width="800" height="741" loading="lazy"><figcaption>captura de pantalla del estado de console.log de firstName y lastName</figcaption></figure><p>¡Espera! ¿Qué ha pasado aquí, amigo? ¡El registro de la consola muestra un cambio antes del cambio en el formulario actual! ¿Por qué está pasando esto?</p><h3 id="-setstate-es-as-ncrono-">¡¡setState es asíncrono!!</h3><p>Ya lo sabíamos, ¡pero ahora lo estamos viendo con nuestros propios ojos! ¿Lo que está pasando allí? Echemos un vistazo a los métodos <code>handleFormChange</code> y <code>logFields</code> anteriores.</p><p>Entonces, el método <code>handleFormChange</code> recibe el nombre y el valor del evento, luego hace un <code>setState</code> de estos datos. Luego llama a <code>handleCounter</code> para actualizar la información del contador y, al final, invoca el método <code>logFields.</code> El método <code>logFields</code> toma el estado actual <code>currentState</code> y devuelve 'Eduard' en lugar de 'Eduardo'.</p><p>La cosa es: <code>setState</code> es asíncrono y no actúa en el momento. React está haciendo su trabajo y ejecuta primero el método <code>logFields</code>, dejando <code>setState</code> para el siguiente ciclo de eventos.</p><p>Pero, ¿cómo podemos evitar este tipo de situaciones?</p><p>Bien, la API <code>setState</code> tiene una <code>callback</code> (devolución de llamada) para evitar esta situación:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/17.png" class="kg-image" alt="17" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/17.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/17.png 670w" width="670" height="376" loading="lazy"><figcaption>método API setState</figcaption></figure><p>Si queremos que <code>logFields()</code> tenga en cuenta los cambios recientes que hemos realizado en el estado, debemos invocarlo dentro de la devolución de llamada, así:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/18.png" class="kg-image" alt="18" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/18.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/18.png 796w" sizes="(min-width: 720px) 720px" width="796" height="580" loading="lazy"><figcaption>utilizando el controlador de devolución de llamada del método setState() API</figcaption></figure><p>Bien, ¡ahora está funcionando!</p><p>Le decimos a React: “¡Oye, React! Ten cuidado de que cuando invoques el método <code>logFields</code>, quiero que tenga el estado ya actualizado, ¿de acuerdo? ¡Confío en ti!"</p><p>React dice: “¡Está bien, Edo! ¡Voy a encargarme de todo este montón de cosas que suelo hacer en el patio trasero con <code>setState</code> y solo cuando termine con eso invocaré <code>logField()</code>! Tranquilo colega! Relájate!”</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/19.png" class="kg-image" alt="19" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/19.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/19.png 800w" sizes="(min-width: 720px) 720px" width="800" height="741" loading="lazy"><figcaption>screenshot of the console.log() of fullName</figcaption></figure><p>Y, de hecho, ¡funcionó!</p><p>¡Bien todos! En este momento hemos manejado los principales escollos de <code>setState</code>.</p><p>¿Tienes el coraje de ir más allá? Toma una taza de café y pongámonos realmente chulos.</p><h3 id="poni-ndose-elegantes-con-setstate-">Poniéndose elegantes con setState( )</h3><p>Ahora que tenemos los métodos <code>handleCounter</code> y <code>handleIsValid</code>, y <code>setState()</code> expresado con funciones, ¡podemos componer la actualización de estado con otras funciones! ¡<strong>Me gusta la composición! ¡Vamos a divertirnos un poco!</strong></p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/20.png" class="kg-image" alt="20" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/20.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/20.png 732w" sizes="(min-width: 720px) 720px" width="732" height="784" loading="lazy"><figcaption>abstrayendo handleIsValid</figcaption></figure><p>Podemos llevar la lógica dentro de <code>setState</code> a una función fuera del componente de clase. Llamémoslo <code>toggleIsValid</code>. ☝️</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/21.png" class="kg-image" alt="21" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/21.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/21.png 716w" width="716" height="512" loading="lazy"><figcaption>función toggleIsValid</figcaption></figure><p>Ahora esta función puede vivir fuera del componente de clase, en cualquier lugar de su aplicación.</p><p>¿Qué pasa si usamos una función de orden superior?</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/22.png" class="kg-image" alt="22" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/22.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/22.png 800w" sizes="(min-width: 720px) 720px" width="800" height="453" loading="lazy"><figcaption>cambiando toggleIsValid por una función de orden superior</figcaption></figure><p>Guau! Ahora ya no estamos invocando la función <code>toggleIsValid</code>. Invocamos una función abstracta de orden superior llamada <code>toggleKey</code> y le pasamos una clave (una cadena en este caso).</p><p>¿Cómo necesitamos cambiar la función <code>toggleIsValid</code> ahora?</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/23.png" class="kg-image" alt="23" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/23.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/23.png 764w" sizes="(min-width: 720px) 720px" width="764" height="512" loading="lazy"><figcaption>función de orden superior toggleKey</figcaption></figure><p>¡¿Qué?! Ahora tenemos una función llamada <code>toggleKey</code> que recibe una clave y devuelve una nueva función que cambia de estado según la clave suministrada.</p><p>Esta <code>toggleKey</code> puede estar en una biblioteca o en un archivo auxiliar. Se puede invocar en muchos contextos diferentes para cambiar el estado de lo que quieras a su opuesto.</p><p>¡Genial!</p><p>Hagamos lo mismo con el controlador del contador de incrementos:</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/24.png" class="kg-image" alt="24" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/24.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/24.png 800w" sizes="(min-width: 720px) 720px" width="800" height="601" loading="lazy"><figcaption>abstracción handleCounter para invocar una función de orden superior</figcaption></figure><p>‌</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/25.png" class="kg-image" alt="25" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/25.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/25.png 800w" sizes="(min-width: 720px) 720px" width="800" height="469" loading="lazy"><figcaption>función de orden superior incrementCounter</figcaption></figure><p>‌¡Sí! ¡Funciona! Que guay! Vamos a volvernos locos ahora...</p><h3 id="disparando-a-la-luna-y-regresando">Disparando a la luna y regresando</h3><p>¿Qué sucede si creamos una función <code>makeUpdater</code> genérica que recibe la función de transformación que desea aplicar, toma la clave y devuelve la función de estado que administra el estado con la función de transformación y la clave? ¿Un poco confundido? ¡Vamos!</p><figure class="kg-card kg-image-card kg-card-hascaption"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/26.png" class="kg-image" alt="26" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/26.png 600w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/26.png 800w" sizes="(min-width: 720px) 720px" width="800" height="390" loading="lazy"><figcaption>función de orden superior makeUpdater</figcaption></figure><p>Ok, eso es suficiente... Nos paramos aquí</p><p>Puedes consultar todo el código que hemos hecho en este <a href="https://github.com/evedes/variations-in-set-state">repositorio de GitHub</a>.</p><h3 id="por-ltimo-pero-no-menos-importante">Por último, pero no menos importante</h3><p>No olvides evitar al máximo el uso del estado y respetar la cascada de propiedades de renderizado de React.</p><p>No olvides que <code>setState</code> es asíncrono.</p><p>No olvides que <code>setState</code> puede tomar un objeto o una función</p><p>No olvides que debes pasar una función cuando tu próximo estado dependa de su estado anterior.</p><p>¡Muchas gracias!</p> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Cómo borrar entradas en campos de valores de formularios dinámicos en React ]]>
                </title>
                <description>
                    <![CDATA[ Hay mucho que considerar cuando se trabaja en una aplicación React, especialmente cuando se trata de formularios. Incluso si puede crear un botón de envío y actualizar el estado de su aplicación de la manera que desee, borrar los formularios puede ser difícil. Digamos que su aplicación tiene formularios dinámicos ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/como-borrar-entradas-en-campos-de-valores-de-formularios-dinamicos-en-react/</link>
                <guid isPermaLink="false">635ba7aa2b42f608ea5f0245</guid>
                
                    <category>
                        <![CDATA[ React ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Sabalete Rodriguez ]]>
                </dc:creator>
                <pubDate>Wed, 30 Nov 2022 03:19:05 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2022/10/5f9c9a92740569d1a4ca2665.jpg" 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-clear-input-values-of-dynamic-form-in-react/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">How to Clear Input Values of Dynamic Form in React</a>
      </p><p>Hay mucho que considerar cuando se trabaja en una aplicación React, especialmente cuando se trata de formularios. Incluso si puede crear un botón de envío y actualizar el estado de su aplicación de la manera que desee, borrar los formularios puede ser difícil.</p><p>Digamos que su aplicación tiene formularios dinámicos como este:</p><figure class="kg-card kg-code-card"><pre><code class="language-jsx">import React from "react";
import Form from "./Form";

const Cart = props =&gt; {
  return (
    &lt;div&gt;
      &lt;Form Items={props.Items} onChangeText={props.onChangeText} /&gt;

      &lt;button onClick={props.handleSubmit}&gt;Submit&lt;/button&gt;
      &lt;button onClick={props.handleReset}&gt;Reset&lt;/button&gt;
    &lt;/div&gt;
  );
};

export default Cart;
</code></pre><figcaption>Cart.js</figcaption></figure><figure class="kg-card kg-code-card"><pre><code class="language-jsx">import React from "react";

const Form = props =&gt; {
  return (
    &lt;div&gt;
      {props.Items.map((item, index) =&gt; (
        &lt;input
          name={item.name}
          placeholder={item.description}
          data-type={item.dtype}
          data-group={item.group}
          onChange={e =&gt; props.onChangeText(e)}
          key={index}
        /&gt;
      ))}
    &lt;/div&gt;
  );
};
export default Form;
</code></pre><figcaption>Form.js</figcaption></figure><p>Y los cuadros de entrada simples se representan en la página:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/06/image-56.png" class="kg-image" alt="image-56" width="600" height="400" loading="lazy"></figure><p>Cuando un usuario ingresa texto en uno de los cuadros de entrada, se guarda en el estado de la aplicación en grupos como este:</p><pre><code>Itemvalues:
  0:
    groupA: 
            item1: itemvalue1
            item2: itemvalue2
    groupB: 
            item3: itemvalue3
            item4: itemvalue4</code></pre><p>Es bastante complicado, pero conseguiste que funcionara.</p><p>En <code>handleReset</code>, puedes restablecer los valores de <code>itemvalues</code> a un estado null cuando se presiona el botón "Reset":</p><pre><code class="language-js">handleReset = () =&gt; {
  this.setState({
    itemvalues: [{}]
  });
};</code></pre><p>Pero el problema es que el texto no se borra de todos los cuadros de entrada:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/06/Peek-2020-06-16-21-32.gif" class="kg-image" alt="Peek-2020-06-16-21-32" width="600" height="400" loading="lazy"></figure><p>Ya has manejado el almacenamiento del texto real en el estado, así que aquí hay una forma sencilla de borrar el texto de todos los cuadros de entrada.</p><h2 id="c-mo-borrar-los-valores-de-todos-los-campos-de-entrada">Cómo borrar los valores de todos los campos de entrada</h2><p>En la parte superior de <code>handleReset</code>, use <code>document.querySelectorAll('input')</code> para seleccionar todos los campos de entrada de la página:</p><pre><code class="language-js">handleReset = () =&gt; {
  document.querySelectorAll('input');
  this.setState({
    itemvalues: [{}]
  });
};</code></pre><p><code>document.querySelectorAll('input')</code> devuelve un <code>NodeList</code>, lo cual es un poco diferente a un arreglo, así que no puedes usar ninguno de los útiles métodos de arreglos con él.</p><p>Para convertirlo en un arreglo, pasa <code>document.querySelectorAll('input')</code> a <code>Array.from()</code>:</p><pre><code class="language-js">handleReset = () =&gt; {
  Array.from(document.querySelectorAll('input'));
  this.setState({
    itemvalues: [{}]
  });
};</code></pre><p>Ahora todo lo que tienes que hacer es iterar a través de cada una de las entradas y establecer su atributo de <code>value</code> a una cadena vacía. El método <code>forEach</code> es un buen candidato para esto:</p><pre><code class="language-js">handleReset = () =&gt; {
  Array.from(document.querySelectorAll("input")).forEach(
    input =&gt; (input.value = "")
  );
  this.setState({
    itemvalues: [{}]
  });
};</code></pre><p>Ahora, cuando un usuario presiona el botón "Reset", el valor de cada entrada también se borra:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/news/content/images/2020/06/Peek-2020-06-16-21-42.gif" class="kg-image" alt="Peek-2020-06-16-21-42" width="600" height="400" loading="lazy"></figure> ]]>
                </content:encoded>
            </item>
        
            <item>
                <title>
                    <![CDATA[ Los principios SOLID de programación orientada a objetos explicados en Español sencillo ]]>
                </title>
                <description>
                    <![CDATA[ Los Principios SOLID tienen cinco principios de diseño de clases Orientado a Objetos. Son un conjunto de reglas y mejores prácticas a seguir al diseñar una estructura de clase. Estos cinco principios nos ayudan a comprender la necesidad de ciertos patrones de diseño y arquitectura de software en general. Así ]]>
                </description>
                <link>https://www.freecodecamp.org/espanol/news/los-principios-solid-explicados-en-espanol/</link>
                <guid isPermaLink="false">63554d352b42f608ea5efb0b</guid>
                
                    <category>
                        <![CDATA[ Programación ]]>
                    </category>
                
                <dc:creator>
                    <![CDATA[ David Sabalete Rodriguez ]]>
                </dc:creator>
                <pubDate>Mon, 28 Nov 2022 20:37:16 +0000</pubDate>
                <media:content url="https://www.freecodecamp.org/espanol/news/content/images/2022/10/solid.png" medium="image" />
                <content:encoded>
                    <![CDATA[ <p data-test-label="translation-intro">
        <strong>Artículo original:</strong> <a href="https://www.freecodecamp.org/news/solid-principles-explained-in-plain-english/" target="_blank" rel="noopener noreferrer" data-test-label="original-article-link">The SOLID Principles of Object-Oriented Programming Explained in Plain English</a>
      </p><p>Los Principios SOLID tienen cinco principios de diseño de clases Orientado a Objetos. Son un conjunto de reglas y mejores prácticas a seguir al diseñar una estructura de clase.</p><p>Estos cinco principios nos ayudan a comprender la necesidad de ciertos patrones de diseño y arquitectura de software en general. Así que creo que es un tema que todo desarrollador debería aprender.</p><p>Este artículo te enseñará todo lo que necesitas saber para aplicar los principios SOLID a tus proyectos.</p><p>Empezaremos echando un vistazo a la historia de este término. Luego vamos a entrar en los detalles esenciales, los por qué y cómo de cada principio, creando un diseño de clase y mejorándolo paso a paso.</p><p>¡Así que toma una taza de café, mate o té y empecemos!</p><h2 id="antecedentes">Antecedentes</h2><p>Los principios SOLID fueron introducidos por primera vez por el famoso científico informático Robert J. Martin (también conocido como el tío Bob) en uno de sus artículos en 2000. Pero el acrónimo SOLID fue introducido más tarde por Michael Feathers.</p><p>El tío Bob también es el autor de los libros best-sellers <em>Clean Code</em> y <em>Clean Architecture</em>, y es uno de los participantes de la "<a href="https://agilemanifesto.org/history.html">Alianza Agile</a>".</p><p>Por lo tanto, no sorprende que todos estos conceptos de codificación limpia, arquitectura orientada a objetos y patrones de diseño estén de alguna manera conectados y se complementen entre sí.</p><p>Todos tienen el mismo propósito:</p><blockquote>"Para crear código comprensible, legible y comprobable en el que muchos desarrolladores puedan trabajar en colaboración."</blockquote><p>Veamos cada principio uno por uno. Siguiendo el acrónimo inglés SOLID, son:</p><ul><li>El Principio de responsabilidad única (<strong>S</strong>ingle Responsibility Principle)</li><li>El Principio Abierto-Cerrado (<strong>O</strong>pen-Closed Principle)</li><li>El Principio de sustitución de Liskov (<strong>L</strong>iskov Substitution Principle) </li><li>El Principio de segregación de interfaz (<strong>I</strong>nterface Segregation Principle) </li><li>El Principio de inversión de dependencia (<strong>D</strong>ependency Inversion Principle) </li></ul><h2 id="principio-de-responsabilidad-nica">Principio de responsabilidad única</h2><p>El Principio de Responsabilidad Única dice que <strong>una clase debe hacer una cosa y, por lo tanto, debe tener una sola razón para cambiar.</strong></p><p>Para enunciar este principio más técnicamente: Solo un cambio potencial (lógica de base de datos, lógica de registro, etc.) en la especificación del software debería poder afectar la especificación de la clase.</p><p>Esto significa que si una clase es un contenedor de datos, como una clase Libro o una clase Estudiante, y tiene algunos campos relacionados con esa entidad, debería cambiar solo cuando cambiamos el modelo de datos.</p><p>Es importante seguir el principio de responsabilidad única. En primer lugar, debido a que muchos equipos diferentes pueden trabajar en el mismo proyecto y editar la misma clase por diferentes motivos, esto podría dar lugar a módulos incompatibles.</p><p>En segundo lugar, facilita el control de versiones. Por ejemplo, digamos que tenemos una clase de persistencia que maneja las operaciones de la base de datos y vemos un cambio en ese archivo en las confirmaciones de GitHub. Al seguir el PRU, sabremos que está relacionado con el almacenamiento o con cosas relacionadas con la base de datos.</p><p>Los conflictos de fusión son otro ejemplo. Aparecen cuando diferentes equipos modifican el mismo archivo. Pero si se sigue el PRU, aparecerán menos conflictos: los archivos tendrán una sola razón para cambiar y los conflictos que existen serán más fáciles de resolver.</p><h3 id="trampas-comunes-y-anti-patrones">Trampas comunes y Anti-patrones</h3><p>En esta sección, veremos algunos errores comunes que violan el Principio de Responsabilidad Única. Luego hablaremos sobre algunas formas de solucionarlos.</p><p>Veremos el código de un programa simple de facturación de librería como ejemplo. Comencemos definiendo una clase de libro para usar en nuestra factura.</p><pre><code class="language-java">class Libro {
	String nombre;
	String nombreAutor;
	int anyo;
	int precio;
	String isbn;

	public Libro(String nombre, String nombreAutor, int anyo, int precio, String isbn) {
		this.nombre = nombre;
		this.nombreAutor = nombreAutor;
		this.anyo = anyo;
        this.precio = precio;
		this.isbn = isbn;
	}
}
</code></pre><p>Esta es una clase de libro simple con algunos campos. Nada sofisticado. No estoy haciendo que los campos sean privados para que no tengamos que lidiar con getters y setters y podamos centrarnos en la lógica.</p><p>Ahora vamos a crear la clase de factura que contendrá la lógica para crear la factura y calcular el precio total. Por ahora, suponga que nuestra librería solo vende libros y nada más.</p><pre><code class="language-java">public class Factura {

	private Libro libro;
	private int cantidad;
	private double tasaDescuento;
	private double tasaImpuesto;
	private double total;

	public Factura(Libro libro, int cantidad, double tasaDescuento, double tasaImpuesto) {
		this.libro = libro;
		this.cantidad = cantidad;
		this.tasaDescuento = tasaDescuento;
		this.tasaImpuesto = tasaImpuesto;
		this.total = this.calculaTotal();
	}

	public double calculaTotal() {
	        double precio = ((libro.precio - libro.precio * tasaDescuento) * this.cantidad);

		double precioConImpuestos = precio * (1 + tasaImpuesto);

		return precioConImpuestos;
	}

	public void imprimeFactura() {
            System.out.println(cantidad + "x " + libro.nombre + " " +          libro.precio + "$");
            System.out.println("Tasa de Descuento: " + tasaDescuento);
            System.out.println("Tasa de Impuesto: " + tasaImpuesto);
            System.out.println("Total: " + total);
	}

        public void guardarArchivo(String nombreArchivo) {
	// Crea un archivo con el nombre dado y escribe la factura.
	}

}</code></pre><p>Aquí está nuestra clase de Factura. También contiene algunos campos sobre facturación y 3 métodos:</p><ul><li><strong>calculaTotal </strong>método que calcula el precio total,</li><li><strong>imprimeFactura</strong> método que debería imprimir la factura por consola, y</li><li><strong>guardaArchivo </strong>método responsable de escribir la factura en un archivo.</li></ul><p>Debe darse un segundo para pensar en lo que está mal con este diseño de clase antes de leer el siguiente párrafo.</p><p>Bien, entonces, ¿qué está pasando aquí? Nuestra clase viola el Principio de Responsabilidad Única de múltiples maneras.</p><p>La primera violación es el método <strong>imprimeFactura</strong>, el cual contiene nuestra lógica de impressión. El PRU establece que nuestra clase solo debería tener una única razón para cambiar, y esa razón debería ser un cambio en el cálculo de la factura para nuestra clase.</p><p>Pero en esta arquitectura, si queremos cambiar el formato de impresión, necesitaríamos cambiar la clase. Esta es la razón por la que no deberíamos tener lógica de impresión mezclada con lógica de negocios en la misma clase.</p><p>Hay otro método que viola el PRU en nuestra clase: el método <strong>guardarArchivo</strong>. También es un error extremadamente común mezclar la lógica de persistencia con la lógica de negocios.</p><p>No piense solo en términos de escribir en un archivo, podría ser guardarlo en una base de datos, hacer una llamada a la API u otras cosas relacionadas con la persistencia.</p><p>Entonces, ¿cómo podemos arreglar esta función de impresión?, puede preguntar.</p><p>Podemos crear nuevas clases para nuestra lógica de impresión y persistencia, por lo que ya no necesitaremos modificar la clase de factura para esos fines.</p><p>Creamos 2 clases, <strong>FacturaImpresion</strong> y <strong>FacturaPersistencia,</strong> y movemos los métodos.</p><pre><code class="language-java">public class FacturaImpresion {
    private Factura factura;

    public FacturaImpresion(Factura factura) {
        this.factura = factura;
    }

    public void imprimir() {
        System.out.println(factura.cantidad + "x " + factura.libro.nombre + " " + factura.libro.precio + " $");
        System.out.println("Tasa de Descuento: " + factura.tasaDescuento);
        System.out.println("Tasa de Impuesto: " + factura.tasaImpuesto);
        System.out.println("Total: " + factura.total + " $");
    }
}</code></pre><pre><code class="language-java">public class FacturaPersistencia {
    Factura factura;

    public FacturaPersistencia(Factura factura) {
        this.factura = factura;
    }

    public void guardarArchivo(String nombreArchivo) {
        // Crea un archivo con el nombre dado y escribe la factura.
    }
}</code></pre><p>Ahora nuestra estructura de clases obedece al principio de responsabilidad única y cada clase es responsable de un aspecto de nuestra aplicación. ¡Excelente!</p><h2 id="principio-de-apertura-y-cierre">Principio de apertura y cierre</h2><p>El principio de apertura y cierre exige que <strong>las clases deban estar abiertas a la extensión y cerradas a la modificación.</strong></p><p>Modificación significa cambiar el código de una clase existente y extensión significa agregar una nueva funcionalidad.</p><p>Entonces, lo que este principio quiere decir es: Deberíamos poder agregar nuevas funciones sin tocar el código existente para la clase. Esto se debe a que cada vez que modificamos el código existente, corremos el riesgo de crear errores potenciales. Por lo tanto, debemos evitar tocar el código de producción probado y confiable (en su mayoría) si es posible.</p><p>Pero, ¿cómo vamos a agregar una nueva funcionalidad sin tocar la clase?, puede preguntarse. Por lo general, se hace con la ayuda de interfaces y clases abstractas.</p><p>Ahora que hemos cubierto los conceptos básicos del principio, apliquémoslo a nuestra aplicación Factura.</p><p>Digamos que nuestro jefe vino a nosotros y dijo que quiere que las facturas se guarden en una base de datos para que podamos buscarlas fácilmente. Creemos que está bien, esto es fácil jefe, ¡solo dame un segundo!</p><p>Creamos la base de datos, nos conectamos a ella y agregamos un método de guardado a nuestra clase <strong>FacturaPersistencia</strong>:</p><pre><code class="language-java">public class FacturaPersistencia {
    Factura factura;

    public FacturaPersistencia(Factura factura) {
        this.factura = factura;
    }

    public void guardarArchivo(String nombreArchivo) {
        // Crea un archivo con el nombre dado y escribe la factura.
    }

    public void guardarEnBaseDatos() {
        // Guarda la factura en la base de datos
    }
}</code></pre><p>Lamentablemente, nosotros, como desarrolladores perezosos de la librería, no diseñamos las clases para que fueran fácilmente ampliables en el futuro. Entonces, para agregar esta función, hemos modificado la clase FacturaPersistencia.</p><p>Si nuestro diseño de clase obedeciera al principio Abierto-Cerrado, no necesitaríamos cambiar esta clase.</p><p>Entonces, como el desarrollador perezoso pero inteligente de la librería, vemos el problema de diseño y decidimos refactorizar el código para obedecer el principio.</p><pre><code class="language-java">interface FacturaPersistencia {

    public void guardar(Factura factura);
}</code></pre><p>Cambiamos el tipo de <strong>FacturaPersistencia</strong> a Interface y agregamos un método de guardado. Cada clase de persistencia implementará este método de guardado.</p><pre><code class="language-java">public class BaseDeDatosPersistencia implements FacturaPersistencia {

    @Override
    public void guardar(Factura factura) {
        // Guardar en la base de datos
    }
}</code></pre><pre><code class="language-java">public class ArchivoPersistencia implements FacturaPersistencia {

    @Override
    public void guardar(Factura factura) {
        // Guardar en archivo
    }
}</code></pre><p>Así que nuestra estructura de clases ahora se ve así:</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/SOLID-Tutorial-1.png" class="kg-image" alt="SOLID-Tutorial-1-1024x554" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/SOLID-Tutorial-1.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2022/10/SOLID-Tutorial-1.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/SOLID-Tutorial-1.png 1024w" sizes="(min-width: 720px) 720px" width="1024" height="554" loading="lazy"></figure><p>Ahora nuestra lógica de persistencia es fácilmente extensible. Si nuestro jefe nos pide que agreguemos otra base de datos y tengamos 2 tipos diferentes de bases de datos como MySQL y MongoDB, podemos hacerlo fácilmente.</p><p>Puede pensar que podríamos simplemente crear múltiples clases sin una interfaz y agregar un método de guardado para todas ellas.</p><p>Pero supongamos que ampliamos nuestra aplicación y tenemos varias clases de persistencia como <strong>FacturaPersistencia</strong>, <strong>LibroPersistencia</strong> y creamos una clase <strong>AdministradorPersistencia</strong> que administra todas las clases de persistencia:</p><pre><code class="language-java">public class AdministradorPersistencia {
    FacturaPersistencia facturaPersistencia;
    LibroPersistencia libroPersistencia;
    
    public AdministradorPersistencia(FacturaPersistencia facturaPersistencia, LibroPersistencia libroPersistencia) {
        this.facturaPersistencia = facturaPersistencia;
        this.libroPersistencia = libroPersistencia;
    }
}</code></pre><p>Ahora podemos pasar cualquier clase que implemente la interfaz <strong>FacturaPersistencia</strong> a esta clase con la ayuda del polimorfismo. Esta es la flexibilidad que proporcionan las interfaces.</p><h2 id="principio-de-sustituci-n-de-liskov">Principio de sustitución de Liskov</h2><p>El Principio de Sustitución de Liskov establece que las subclases deben ser sustituibles por sus clases base.</p><p>Esto significa que, dado que la clase B es una subclase de la clase A, deberíamos poder pasar un objeto de la clase B a cualquier método que espere un objeto de la clase A y el método no debería dar ningún resultado extraño en ese caso.</p><p>Este es el comportamiento esperado, porque cuando usamos la herencia asumimos que la clase secundaria hereda todo lo que tiene la superclase. La clase secundaria extiende el comportamiento pero nunca lo reduce.</p><p>Por lo tanto, cuando una clase no obedece este principio, genera algunos errores desagradables que son difíciles de detectar.</p><p>El principio de Liskov es fácil de entender, pero difícil de detectar en el código. Así que veamos un ejemplo.</p><pre><code class="language-java">class Rectangulo {
	protected int ancho, alto;

	public Rectangulo() {
	}

	public Rectangulo(int ancho, int alto) {
		this.ancho = ancho;
		this.alto = alto;
	}

	public int getAncho() {
		return ancho;
	}

	public void setAncho(int ancho) {
		this.ancho = ancho;
	}

	public int getAlto() {
		return alto;
	}

	public void setAlto(int alto) {
		this.alto = alto;
	}

	public int getArea() {
		return ancho * alto;
	}
}</code></pre><p>Tenemos una clase Rectángulo simple y una función <strong>getArea</strong> que devuelve el área del rectángulo.</p><p>Ahora decidimos crear otra clase para Cuadrados. Como sabrás, un cuadrado es solo un tipo especial de rectángulo donde el ancho es igual a la altura.</p><pre><code class="language-java">class Cuadrado extends Rectangulo {
	public Cuadrado() {}

	public Cuadrado(int talla) {
		ancho = alto = talla;
	}

	@Override
	public void setAncho(int ancho) {
		super.setAncho(ancho);
		super.setAlto(ancho);
	}

	@Override
	public void setAlto(int alto) {
		super.setAlto(alto);
		super.setAncho(alto);
	}
}</code></pre><p>Nuestra clase Cuadrado amplía la clase Rectángulo. Establecemos alto y ancho en el mismo valor en el constructor, pero no queremos que ningún cliente (alguien que use nuestra clase en su código) cambie el alto o el peso de una manera que pueda violar la propiedad cuadrada.</p><p>Por lo tanto, anulamos los setters para establecer ambas propiedades cada vez que se cambia una de ellas. Pero al hacerlo acabamos de violar el principio de sustitución de Liskov.</p><p>Vamos a crear una clase principal para realizar pruebas en la función <strong>getArea</strong>.</p><pre><code class="language-java">class Test {

   static void getAreaTest(Rectangulo r) {
      int ancho = r.getAncho();
      r.setAlto(10);
      System.out.println("Area esperada de " + (ancho * 10) + ", tiene " + r.getArea());
   }

   public static void main(String[] args) {
      Rectangulo rc = new Rectangulo(2, 3);
      getAreaTest(rc);

      Rectangulo sq = new Cuadrado();
      sq.setAncho(5);
      getAreaTest(sq);
   }
}</code></pre><p>Al probador de su equipo se le ocurrió la función de prueba <strong>getAreaTest</strong> y le dice que su función <strong>getArea</strong> no pasa la prueba de objetos cuadrados.</p><p>En la primera prueba, creamos un rectángulo donde el ancho es 2 y la altura es 3 y llamamos a <strong>getAreaTest</strong>. La salida es 20 como se esperaba, pero las cosas salen mal cuando pasamos en la plaza. Esto se debe a que la llamada a la función <strong>setAlto</strong> en la prueba también establece el ancho y da como resultado un resultado inesperado.</p><h2 id="principio-de-segregaci-n-de-interfaces">Principio de segregación de interfaces</h2><p>La segregación significa mantener las cosas separadas, y el Principio de Segregación de Interfaces se trata de separar las interfaces.</p><p>El principio establece que muchas interfaces específicas del cliente son mejores que una interfaz de propósito general. No se debe obligar a los clientes a implementar una función que no necesitan.</p><p>Este es un principio simple de entender y aplicar, así que veamos un ejemplo.</p><pre><code class="language-java">public interface Estacionamiento {

	void aparcarCoche(); // Reducir el recuento de puntos vacíos en 1
	void sacarCoche(); // Aumenta los espacios vacíos en 1
	void getCapacidad(); // Devuelve la capacidad del coche
	double calcularTarifa(Coche coche); // Devuelve el precio en función del número de horas.
	void hacerPago(Coche coche);
}

class Coche {

}</code></pre><p>Modelamos un estacionamiento muy simplificado. Es el tipo de estacionamiento donde pagas una tarifa por hora. Ahora considere que queremos implementar un estacionamiento que sea gratuito.</p><pre><code class="language-java">public class EstacionamientoGratis implements Estacionamiento {

	@Override
	public void aparcarCoche() {
		
	}

	@Override
	public void sacarCoche() {

	}

	@Override
	public void getCapacidad() {

	}

	@Override
	public double calcularTarifa(Coche coche) {
		return 0;
	}

	@Override
	public void hacerPago(Coche coche) {
		throw new Exception("Estacionamiento es gratis");
	}
}</code></pre><p>Nuestra interfaz de estacionamiento se componía de 2 cosas: lógica relacionada con el estacionamiento (aparcar coche, sacar automóvil, obtener capacidad) y lógica relacionada con el pago.</p><p>Pero es demasiado específico. Debido a eso, nuestra clase EstacionamientoGratis se vio obligada a implementar métodos relacionados con el pago que son irrelevantes. Separemos o segreguemos las interfaces.</p><figure class="kg-card kg-image-card"><img src="https://www.freecodecamp.org/espanol/news/content/images/2022/10/SOLID-Tutorial-1024x432.png" class="kg-image" alt="SOLID-Tutorial-1024x432" srcset="https://www.freecodecamp.org/espanol/news/content/images/size/w600/2022/10/SOLID-Tutorial-1024x432.png 600w, https://www.freecodecamp.org/espanol/news/content/images/size/w1000/2022/10/SOLID-Tutorial-1024x432.png 1000w, https://www.freecodecamp.org/espanol/news/content/images/2022/10/SOLID-Tutorial-1024x432.png 1024w" sizes="(min-width: 720px) 720px" width="1024" height="432" loading="lazy"></figure><p>Ahora hemos separado el estacionamiento. Con este nuevo modelo, incluso podemos ir más allá y dividir <strong>EstacionamientoPagado</strong> para admitir diferentes tipos de pago.</p><p>Ahora nuestro modelo es mucho más flexible, extensible y los clientes no necesitan implementar ninguna lógica irrelevante porque solo proporcionamos funcionalidad relacionada con el estacionamiento en la interfaz del estacionamiento.</p><h2 id="principio-de-inversi-n-de-dependencia">Principio de inversión de dependencia</h2><p>El principio de inversión de dependencia establece que nuestras clases deben depender de interfaces o clases abstractas en lugar de clases y funciones concretas.</p><p>En su <a href="https://fi.ort.edu.uy/innovaportal/file/2032/1/design_principles.pdf">artículo</a> (2000), el tío Bob resume este principio de la siguiente manera:</p><blockquote>"Si el PAC establece el objetivo de la arquitectura OO, el PID establece el mecanismo principal".</blockquote><p>Estos dos principios están realmente relacionados y hemos aplicado este patrón antes mientras discutíamos el Principio Abierto-Cerrado.</p><p>Queremos que nuestras clases estén abiertas a la extensión, por lo que hemos reorganizado nuestras dependencias para que dependan de interfaces en lugar de clases concretas. Nuestra clase <strong>AdministradorPersistencia</strong> depende de <strong>FacturaPersistencia</strong> en lugar de las clases que implementan esa interfaz.</p><h2 id="conclusi-n">Conclusión</h2><p>En este artículo, comenzamos con la historia de los principios SOLID y luego tratamos de adquirir una comprensión clara de los por qué y los cómo de cada principio. Incluso refactorizamos una aplicación de Factura simple para obedecer los principios de SOLID.</p><p>Quiero agradecerte por tomarte el tiempo de leer el artículo completo y espero que los conceptos anteriores sean claros.</p><p>Sugiero tener en cuenta estos principios al diseñar, escribir y refactorizar su código para que su código sea mucho más limpio, extensible y comprobable.</p><p>Si estás interesado en leer más artículos como este, puedes suscribirte a la lista de correo de <a href="https://erinc.io/">mi blog</a> para recibir una notificación cuando publique un nuevo artículo. </p><hr> ]]>
                </content:encoded>
            </item>
        
    </channel>
</rss>
