From dabf61a41345e69a81d4129dfd86571b8d2e7515 Mon Sep 17 00:00:00 2001 From: Arnaldo Perez Date: Thu, 8 Feb 2024 16:28:35 -0400 Subject: [PATCH 1/6] =?UTF-8?q?Patrones=20de=20dise=C3=B1o=20de=20react?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../lesson/react-design-patterns.es.md | 242 +++++++++++++++++- src/content/lesson/what-is-react-flux.md | 2 +- 2 files changed, 242 insertions(+), 2 deletions(-) diff --git a/src/content/lesson/react-design-patterns.es.md b/src/content/lesson/react-design-patterns.es.md index 4cdeb906b..30d7a446b 100644 --- a/src/content/lesson/react-design-patterns.es.md +++ b/src/content/lesson/react-design-patterns.es.md @@ -1 +1,241 @@ -# https://codesandbox.io/p/sandbox/higher-order-component-card-vv2grj?file=%2Fsrc%2FPlanetCard.js +## ¿Que son patrones de diseño? + +La programación se trata de escribir instrucciones para ser interpretadas por una maquina, lo que nos lleva en muchos casos a que existan muchas formas de solucionar un mismo problema. Aun asi hay asuntos comunes que se deben considerar a la hora de hacer crecer un sistema o lograr que tenga un buen desempeño si tiene una gran concurrencia, ahi los patrones de diseño nos ayudan a dar solución a estos escenarios. + +> Los patrones de diseño son estrategias para solucionar problemas comunes en la programación. Algunos solucionan problemas de reutilización de código, otros problemas de escalabilidad o eficiencia. No se trata de librerías o frameworks específicos, son mas bien formas de utilizar las herramientas que te ofrece una determinada tecnología, para evitar problemas que ya son bien conocidos y cuyas soluciones ya han sido probadas. + +Los planteamientos de los patrones de diseño se hacen de forma genérica, de manera que puedan ser implementados en contextos específicos con sus propias particularidades. En éste articulo vamos a ver algunos patrones utilizados en React y que sirven para hacer nuestra aplicación mas escalable y eficiente. + +## Componentes de orden superior (Higher order components - HOC) + +Este patrón plantea la creación de componentes que estén diseñados para contener en su interior a otro componente, al mismo tiempo que le agrega funcionalidades. Este componente contenedor, llamado de orden superior, tiene que contemplar funcionalidades comunes que puedan ser requeridas por los demás componentes que serán envueltos con él. + +En este ejemplo tenemos un componente de tarjeta (Card) de bootstrap que tiene una funcionalidad básica, pero que implementa el patrón HOC para que recibir otros componentes como cuerpo de dicha tarjeta. Esto permite tener componentes de tarjeta similares, que comparten funcionalidades comunes, pero que tienen una estructura propia para el contenido. + +```react +// Card.jsx +export default function wrapCard(BodyComponent) { + const CardWrapper = (props) => { + // Esta función será utilizada por todos los componentes envueltos en este + const saveClick = () => { + console.log("Saved props: " + JSON.stringify(props)); + }; + return ( + <> +
+
+
    + {/* Barra de herramienta para las tarjetas*/} +
+
+ {/* Aquí se coloca el componente del cuerpo de la tarjeta*/} + +
+ + ); + }; + return CardWrapper; +} +``` + +A la hora de crear el componente para el cuerpo se debe exportar llamando a la función que lo va a envolver en el componente de nivel superior. + +```react +// Character.jsx +import wrapCard from "./Card"; + +const CharacterCard = ({ character }) => { + return ( + <> +
+ {/* Encabezado de la tarjeta */} +
+
+ {/* Cuerpo de la tarjeta */} +
+ + ); +}; +// Se exporta envuelto en el componente de nivel superior +export default wrapCard(CharacterCard); +``` + +Así como este componente pueden crearse todos los que sean necesarios utilizando el patrón HOC para que todos compartan funcionalidades y estilos. Aquí tienes un ejemplo implementando esta tarjeta: + + + +## Patrón proveedor (Provider) + +Este patrón se popularizo en la comunidad de React desde que se introdujo la api de contexto (Context API), se trata de básicamente de crear un componente que **provee** de un estado a todos los componentes en su interior. Tratándose de aplicaciones que se forman en base a componentes, se pueden crear varias capas de proveedores (cada una dentro de otra) que provean de varios contextos a tu aplicación. + +![Las apps de react son como cebollas](https://breathecode.herokuapp.com/v1/media/file/apps-de-react-son-como-cebollas "Las apps de react son como cebollas"). + +![React apps are like onions](https://breathecode.herokuapp.com/v1/media/file/react-apps-are-like-onions "React apps are like onions"). + +Algunas librerías implementan este patrón por defecto, como por ejemplo React Router que envuelve toda la aplicación en un componente `` y luego te permite crear layouts con rutas dinámicas con el componente ``, creando asi varias capas de proveedores. Si quieres saber más de como usar React Router puedes visitar [éste artículo](https://4geeks.com/es/lesson/routing-our-views-with-react-router-es). +[this article](https://4geeks.com/lesson/routing-our-views-with-react-router). + +Claro que también puedes crear tus propios contextos con lo que necesites, por ejemplo puedes crear un contexto que sirva para cambiar el diseño de tu aplicación de un modo claro a un modo oscuro, veamos como hacerlo: + +```react +// ThemeProvider.jsx +import React, { createContext, useContext, useState } from "react"; + +// Crearemos nuestro contexto y creamos la instancia que se va a exportar +const ThemeContext = createContext(); +function useTheme() { + return useContext(ThemeContext); +} +export default useTheme; + +// Se crea el proveedor para envolver nuestra app, +// usando como valor un estado para el tema +// y una función que alterna entre claro y oscuro. +export function ThemeProvider({ children }) { + const [theme, setTheme] = useState("light"); + const changeTheme = () => { + setTheme(theme === "light" ? "dark" : "light"); + }; + return ( + + {children} + + ); +} +``` + +Luego de esto solo queda envolver nuestra aplicación en el proveedor y empezar a usar el contexto en nuestros componentes. + +```react +// index.jsx +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App"; +import { ThemeProvider } from "./ThemeProvider.jsx"; + +ReactDOM.createRoot(document.getElementById("root")).render( + + {/* El proveedor se usa para envolver el componente raíz de la app */} + + + + , +); +``` + +```react +// App.jsx +import "./App.css"; +// Importamos el contexto de nuestro tema +import useTheme from "./ThemeProvider"; + +export default function App() { + // Accedemos al estado del tema y la función que lo cambia + const { theme, changeTheme } = useTheme(); + return ( +
+

Theme {theme}

+ +
+ ); +} +``` + +Puedes ver otros usos de la api de contexto en [ésta lección](https://4geeks.com/lesson/context-api). Aquí podemos ver el resultado final en funcionamiento: + + +## Patrón de componentes compuestos (Compound components) + +Este patrón plantea la integración de componentes que están hechos para trabajar juntos o muy integrados. Para ello el componente principal crea un contexto y lo expone a los componentes hijos que deben ir dentro, lo que les permite compartir datos y funciones dentro del conjunto. Una librería que implementa este patrón es **React Bootstrap**, que implementa sus formularios como un componente que debe estar integrado por otros subcomponentes para los controles, permitiéndole integrar funciones como la validación de manera conjunta. + +Si bien los componentes hijos se declaran como cualquier otro componente, se suelen exportar como miembros del componente principal, para que en implementación sea mas notoria su integración. + +```react +// Contexto para el conjunto de componentes +const SelectContext = createContext(); + +// Componente principal +const Select = (props) => {...}; + +// Componente hijo +const Option = (props) => {...}; + +// Se agrega al componente principal una propiedad que contiene al hijo +Select.Option = Option; + +export default Select; +``` + + Para el ejemplo crearemos un selector de opciones para un formulario. El componente padre será ` checkOption(value)} + name={name} + value={value} + /> + + + ); +}; +``` + +En esta demostración podemos ver la implementación final de nuestro selector utilizando el patron de componentes compuestos: + + + +## Conclusión + +Como hemos visto los patrones nos ofrecen soluciones a problemas típicos que nos encontramos en el desarrollo de un software. No son mas que una manera ingeniosa de utilizar las herramientas que ya tenemos con React, para que faciliten determinada función. + +No podemos decir que uno sea mejor que otro, solo que cada uno sirve para casos específicos o se adaptan mejor a determinada situación. Tampoco es obligatorio su uso, mas bien es bueno implementarlos en casos donde se necesite escalar en la complejidad, pero para casos muy sencillos puede llegar a ser excesivos. Ahora que conoces estos patrones, piensa en qué proyectos los puedes aprovechar. \ No newline at end of file diff --git a/src/content/lesson/what-is-react-flux.md b/src/content/lesson/what-is-react-flux.md index a6d0f6793..cc5f2aa8c 100644 --- a/src/content/lesson/what-is-react-flux.md +++ b/src/content/lesson/what-is-react-flux.md @@ -222,4 +222,4 @@ export default function ListItem({ task, index }) { We have implemented the logic of our application in a context applying the flux pattern, allowing its use in different components. Now we can see the final result working. - \ No newline at end of file + \ No newline at end of file From d1fd041398e7cb4d7eb4d51bd0e1313b156675d7 Mon Sep 17 00:00:00 2001 From: Arnaldo Perez Date: Thu, 8 Feb 2024 16:31:33 -0400 Subject: [PATCH 2/6] Patrones de componentes react --- .../lesson/react-design-patterns.es.md | 118 +++++++++--------- 1 file changed, 58 insertions(+), 60 deletions(-) diff --git a/src/content/lesson/react-design-patterns.es.md b/src/content/lesson/react-design-patterns.es.md index 30d7a446b..a428660bc 100644 --- a/src/content/lesson/react-design-patterns.es.md +++ b/src/content/lesson/react-design-patterns.es.md @@ -6,72 +6,12 @@ La programación se trata de escribir instrucciones para ser interpretadas por u Los planteamientos de los patrones de diseño se hacen de forma genérica, de manera que puedan ser implementados en contextos específicos con sus propias particularidades. En éste articulo vamos a ver algunos patrones utilizados en React y que sirven para hacer nuestra aplicación mas escalable y eficiente. -## Componentes de orden superior (Higher order components - HOC) - -Este patrón plantea la creación de componentes que estén diseñados para contener en su interior a otro componente, al mismo tiempo que le agrega funcionalidades. Este componente contenedor, llamado de orden superior, tiene que contemplar funcionalidades comunes que puedan ser requeridas por los demás componentes que serán envueltos con él. - -En este ejemplo tenemos un componente de tarjeta (Card) de bootstrap que tiene una funcionalidad básica, pero que implementa el patrón HOC para que recibir otros componentes como cuerpo de dicha tarjeta. Esto permite tener componentes de tarjeta similares, que comparten funcionalidades comunes, pero que tienen una estructura propia para el contenido. - -```react -// Card.jsx -export default function wrapCard(BodyComponent) { - const CardWrapper = (props) => { - // Esta función será utilizada por todos los componentes envueltos en este - const saveClick = () => { - console.log("Saved props: " + JSON.stringify(props)); - }; - return ( - <> -
-
-
    - {/* Barra de herramienta para las tarjetas*/} -
-
- {/* Aquí se coloca el componente del cuerpo de la tarjeta*/} - -
- - ); - }; - return CardWrapper; -} -``` - -A la hora de crear el componente para el cuerpo se debe exportar llamando a la función que lo va a envolver en el componente de nivel superior. - -```react -// Character.jsx -import wrapCard from "./Card"; - -const CharacterCard = ({ character }) => { - return ( - <> -
- {/* Encabezado de la tarjeta */} -
-
- {/* Cuerpo de la tarjeta */} -
- - ); -}; -// Se exporta envuelto en el componente de nivel superior -export default wrapCard(CharacterCard); -``` - -Así como este componente pueden crearse todos los que sean necesarios utilizando el patrón HOC para que todos compartan funcionalidades y estilos. Aquí tienes un ejemplo implementando esta tarjeta: - - - ## Patrón proveedor (Provider) Este patrón se popularizo en la comunidad de React desde que se introdujo la api de contexto (Context API), se trata de básicamente de crear un componente que **provee** de un estado a todos los componentes en su interior. Tratándose de aplicaciones que se forman en base a componentes, se pueden crear varias capas de proveedores (cada una dentro de otra) que provean de varios contextos a tu aplicación. ![Las apps de react son como cebollas](https://breathecode.herokuapp.com/v1/media/file/apps-de-react-son-como-cebollas "Las apps de react son como cebollas"). -![React apps are like onions](https://breathecode.herokuapp.com/v1/media/file/react-apps-are-like-onions "React apps are like onions"). - Algunas librerías implementan este patrón por defecto, como por ejemplo React Router que envuelve toda la aplicación en un componente `` y luego te permite crear layouts con rutas dinámicas con el componente ``, creando asi varias capas de proveedores. Si quieres saber más de como usar React Router puedes visitar [éste artículo](https://4geeks.com/es/lesson/routing-our-views-with-react-router-es). [this article](https://4geeks.com/lesson/routing-our-views-with-react-router). @@ -144,6 +84,64 @@ export default function App() { Puedes ver otros usos de la api de contexto en [ésta lección](https://4geeks.com/lesson/context-api). Aquí podemos ver el resultado final en funcionamiento: +## Componentes de orden superior (Higher order components - HOC) + +Este patrón plantea la creación de componentes que estén diseñados para contener en su interior a otro componente, al mismo tiempo que le agrega funcionalidades. Este componente contenedor, llamado de orden superior, tiene que contemplar funcionalidades comunes que puedan ser requeridas por los demás componentes que serán envueltos con él. + +En este ejemplo tenemos un componente de tarjeta (Card) de bootstrap que tiene una funcionalidad básica, pero que implementa el patrón HOC para que recibir otros componentes como cuerpo de dicha tarjeta. Esto permite tener componentes de tarjeta similares, que comparten funcionalidades comunes, pero que tienen una estructura propia para el contenido. + +```react +// Card.jsx +export default function wrapCard(BodyComponent) { + const CardWrapper = (props) => { + // Esta función será utilizada por todos los componentes envueltos en este + const saveClick = () => { + console.log("Saved props: " + JSON.stringify(props)); + }; + return ( + <> +
+
+
    + {/* Barra de herramienta para las tarjetas*/} +
+
+ {/* Aquí se coloca el componente del cuerpo de la tarjeta*/} + +
+ + ); + }; + return CardWrapper; +} +``` + +A la hora de crear el componente para el cuerpo se debe exportar llamando a la función que lo va a envolver en el componente de nivel superior. + +```react +// Character.jsx +import wrapCard from "./Card"; + +const CharacterCard = ({ character }) => { + return ( + <> +
+ {/* Encabezado de la tarjeta */} +
+
+ {/* Cuerpo de la tarjeta */} +
+ + ); +}; +// Se exporta envuelto en el componente de nivel superior +export default wrapCard(CharacterCard); +``` + +Así como este componente pueden crearse todos los que sean necesarios utilizando el patrón HOC para que todos compartan funcionalidades y estilos. Aquí tienes un ejemplo implementando esta tarjeta: + + + ## Patrón de componentes compuestos (Compound components) Este patrón plantea la integración de componentes que están hechos para trabajar juntos o muy integrados. Para ello el componente principal crea un contexto y lo expone a los componentes hijos que deben ir dentro, lo que les permite compartir datos y funciones dentro del conjunto. Una librería que implementa este patrón es **React Bootstrap**, que implementa sus formularios como un componente que debe estar integrado por otros subcomponentes para los controles, permitiéndole integrar funciones como la validación de manera conjunta. From be3c4c912c98a6546e7ec6145cee47356b1b6e93 Mon Sep 17 00:00:00 2001 From: Arnaldo Perez Date: Thu, 8 Feb 2024 16:32:26 -0400 Subject: [PATCH 3/6] Patrones de componentes react --- src/content/lesson/react-design-patterns.md | 239 ++++++++++++++++++++ 1 file changed, 239 insertions(+) create mode 100644 src/content/lesson/react-design-patterns.md diff --git a/src/content/lesson/react-design-patterns.md b/src/content/lesson/react-design-patterns.md new file mode 100644 index 000000000..f1bf0929a --- /dev/null +++ b/src/content/lesson/react-design-patterns.md @@ -0,0 +1,239 @@ +## ¿Que son patrones de diseño? + +La programación se trata de escribir instrucciones para ser interpretadas por una maquina, lo que nos lleva en muchos casos a que existan muchas formas de solucionar un mismo problema. Aun asi hay asuntos comunes que se deben considerar a la hora de hacer crecer un sistema o lograr que tenga un buen desempeño si tiene una gran concurrencia, ahi los patrones de diseño nos ayudan a dar solución a estos escenarios. + +> Los patrones de diseño son estrategias para solucionar problemas comunes en la programación. Algunos solucionan problemas de reutilización de código, otros problemas de escalabilidad o eficiencia. No se trata de librerías o frameworks específicos, son mas bien formas de utilizar las herramientas que te ofrece una determinada tecnología, para evitar problemas que ya son bien conocidos y cuyas soluciones ya han sido probadas. + +Los planteamientos de los patrones de diseño se hacen de forma genérica, de manera que puedan ser implementados en contextos específicos con sus propias particularidades. En éste articulo vamos a ver algunos patrones utilizados en React y que sirven para hacer nuestra aplicación mas escalable y eficiente. + +## Componentes de orden superior (Higher order components - HOC) + +Este patrón plantea la creación de componentes que estén diseñados para contener en su interior a otro componente, al mismo tiempo que le agrega funcionalidades. Este componente contenedor, llamado de orden superior, tiene que contemplar funcionalidades comunes que puedan ser requeridas por los demás componentes que serán envueltos con él. + +En este ejemplo tenemos un componente de tarjeta (Card) de bootstrap que tiene una funcionalidad básica, pero que implementa el patrón HOC para que recibir otros componentes como cuerpo de dicha tarjeta. Esto permite tener componentes de tarjeta similares, que comparten funcionalidades comunes, pero que tienen una estructura propia para el contenido. + +```react +// Card.jsx +export default function wrapCard(BodyComponent) { + const CardWrapper = (props) => { + // Esta función será utilizada por todos los componentes envueltos en este + const saveClick = () => { + console.log("Saved props: " + JSON.stringify(props)); + }; + return ( + <> +
+
+
    + {/* Barra de herramienta para las tarjetas*/} +
+
+ {/* Aquí se coloca el componente del cuerpo de la tarjeta*/} + +
+ + ); + }; + return CardWrapper; +} +``` + +A la hora de crear el componente para el cuerpo se debe exportar llamando a la función que lo va a envolver en el componente de nivel superior. + +```react +// Character.jsx +import wrapCard from "./Card"; + +const CharacterCard = ({ character }) => { + return ( + <> +
+ {/* Encabezado de la tarjeta */} +
+
+ {/* Cuerpo de la tarjeta */} +
+ + ); +}; +// Se exporta envuelto en el componente de nivel superior +export default wrapCard(CharacterCard); +``` + +Así como este componente pueden crearse todos los que sean necesarios utilizando el patrón HOC para que todos compartan funcionalidades y estilos. Aquí tienes un ejemplo implementando esta tarjeta: + + + +## Patrón proveedor (Provider) + +Este patrón se popularizo en la comunidad de React desde que se introdujo la api de contexto (Context API), se trata de básicamente de crear un componente que **provee** de un estado a todos los componentes en su interior. Tratándose de aplicaciones que se forman en base a componentes, se pueden crear varias capas de proveedores (cada una dentro de otra) que provean de varios contextos a tu aplicación. + +![React apps are like onions](https://breathecode.herokuapp.com/v1/media/file/react-apps-are-like-onions "React apps are like onions"). + +Algunas librerías implementan este patrón por defecto, como por ejemplo React Router que envuelve toda la aplicación en un componente `` y luego te permite crear layouts con rutas dinámicas con el componente ``, creando asi varias capas de proveedores. Si quieres saber más de como usar React Router puedes visitar [éste artículo](https://4geeks.com/es/lesson/routing-our-views-with-react-router-es). +[this article](https://4geeks.com/lesson/routing-our-views-with-react-router). + +Claro que también puedes crear tus propios contextos con lo que necesites, por ejemplo puedes crear un contexto que sirva para cambiar el diseño de tu aplicación de un modo claro a un modo oscuro, veamos como hacerlo: + +```react +// ThemeProvider.jsx +import React, { createContext, useContext, useState } from "react"; + +// Crearemos nuestro contexto y creamos la instancia que se va a exportar +const ThemeContext = createContext(); +function useTheme() { + return useContext(ThemeContext); +} +export default useTheme; + +// Se crea el proveedor para envolver nuestra app, +// usando como valor un estado para el tema +// y una función que alterna entre claro y oscuro. +export function ThemeProvider({ children }) { + const [theme, setTheme] = useState("light"); + const changeTheme = () => { + setTheme(theme === "light" ? "dark" : "light"); + }; + return ( + + {children} + + ); +} +``` + +Luego de esto solo queda envolver nuestra aplicación en el proveedor y empezar a usar el contexto en nuestros componentes. + +```react +// index.jsx +import React from "react"; +import ReactDOM from "react-dom/client"; +import App from "./App"; +import { ThemeProvider } from "./ThemeProvider.jsx"; + +ReactDOM.createRoot(document.getElementById("root")).render( + + {/* El proveedor se usa para envolver el componente raíz de la app */} + + + + , +); +``` + +```react +// App.jsx +import "./App.css"; +// Importamos el contexto de nuestro tema +import useTheme from "./ThemeProvider"; + +export default function App() { + // Accedemos al estado del tema y la función que lo cambia + const { theme, changeTheme } = useTheme(); + return ( +
+

Theme {theme}

+ +
+ ); +} +``` + +Puedes ver otros usos de la api de contexto en [ésta lección](https://4geeks.com/lesson/context-api). Aquí podemos ver el resultado final en funcionamiento: + + +## Patrón de componentes compuestos (Compound components) + +Este patrón plantea la integración de componentes que están hechos para trabajar juntos o muy integrados. Para ello el componente principal crea un contexto y lo expone a los componentes hijos que deben ir dentro, lo que les permite compartir datos y funciones dentro del conjunto. Una librería que implementa este patrón es **React Bootstrap**, que implementa sus formularios como un componente que debe estar integrado por otros subcomponentes para los controles, permitiéndole integrar funciones como la validación de manera conjunta. + +Si bien los componentes hijos se declaran como cualquier otro componente, se suelen exportar como miembros del componente principal, para que en implementación sea mas notoria su integración. + +```react +// Contexto para el conjunto de componentes +const SelectContext = createContext(); + +// Componente principal +const Select = (props) => {...}; + +// Componente hijo +const Option = (props) => {...}; + +// Se agrega al componente principal una propiedad que contiene al hijo +Select.Option = Option; + +export default Select; +``` + + Para el ejemplo crearemos un selector de opciones para un formulario. El componente padre será ` checkOption(value)} + name={name} + value={value} + /> + + + ); +}; +``` + +En esta demostración podemos ver la implementación final de nuestro selector utilizando el patron de componentes compuestos: + + + +## Conclusión + +Como hemos visto los patrones nos ofrecen soluciones a problemas típicos que nos encontramos en el desarrollo de un software. No son mas que una manera ingeniosa de utilizar las herramientas que ya tenemos con React, para que faciliten determinada función. + +No podemos decir que uno sea mejor que otro, solo que cada uno sirve para casos específicos o se adaptan mejor a determinada situación. Tampoco es obligatorio su uso, mas bien es bueno implementarlos en casos donde se necesite escalar en la complejidad, pero para casos muy sencillos puede llegar a ser excesivos. Ahora que conoces estos patrones, piensa en qué proyectos los puedes aprovechar. \ No newline at end of file From 82e41fbb4a9d16b6665a0058330cf78b58f130bf Mon Sep 17 00:00:00 2001 From: Arnaldo Perez Date: Mon, 12 Feb 2024 11:43:25 -0400 Subject: [PATCH 4/6] Traduccion --- src/content/lesson/react-design-patterns.es.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/lesson/react-design-patterns.es.md b/src/content/lesson/react-design-patterns.es.md index a428660bc..14a37dc68 100644 --- a/src/content/lesson/react-design-patterns.es.md +++ b/src/content/lesson/react-design-patterns.es.md @@ -10,7 +10,7 @@ Los planteamientos de los patrones de diseño se hacen de forma genérica, de ma Este patrón se popularizo en la comunidad de React desde que se introdujo la api de contexto (Context API), se trata de básicamente de crear un componente que **provee** de un estado a todos los componentes en su interior. Tratándose de aplicaciones que se forman en base a componentes, se pueden crear varias capas de proveedores (cada una dentro de otra) que provean de varios contextos a tu aplicación. -![Las apps de react son como cebollas](https://breathecode.herokuapp.com/v1/media/file/apps-de-react-son-como-cebollas "Las apps de react son como cebollas"). +![Las apps de react son como cebollas](https://breathecode.herokuapp.com/v1/media/file/apps-de-react-son-como-cebollas "Las apps de react son como cebollas") Algunas librerías implementan este patrón por defecto, como por ejemplo React Router que envuelve toda la aplicación en un componente `` y luego te permite crear layouts con rutas dinámicas con el componente ``, creando asi varias capas de proveedores. Si quieres saber más de como usar React Router puedes visitar [éste artículo](https://4geeks.com/es/lesson/routing-our-views-with-react-router-es). [this article](https://4geeks.com/lesson/routing-our-views-with-react-router). From e1e56186d56a0b02275ff7959fe16c0945d213bf Mon Sep 17 00:00:00 2001 From: Arnaldo Perez <19396163+arnaldoperez@users.noreply.github.com> Date: Thu, 9 May 2024 16:12:02 -0400 Subject: [PATCH 5/6] update useReducer lesson --- ...optimize-react-components-usereducer.es.md | 56 ++++++++++--------- .../optimize-react-components-usereducer.md | 56 ++++++++++++++----- 2 files changed, 71 insertions(+), 41 deletions(-) diff --git a/src/content/lesson/optimize-react-components-usereducer.es.md b/src/content/lesson/optimize-react-components-usereducer.es.md index c3b3c3512..6253f776b 100644 --- a/src/content/lesson/optimize-react-components-usereducer.es.md +++ b/src/content/lesson/optimize-react-components-usereducer.es.md @@ -1,5 +1,5 @@ --- -title: "Qué es y como usar el hook useReducer en React.js" +title: "¿Qué es y cómo usar el hook useReducer en React.js" subtitle: "Aprende a usar el hook useReducer en React.js y cómo funciona, comparalo con otras alternativas como redux, flux, entre otras." cover: "https://www.desktopbackground.org/p/2013/09/13/637935_nasa-wallpapers_1600x1200_h.jpg" textColor: "white" @@ -13,24 +13,16 @@ status: "draft" Los hooks empezaron a existir en react desde la versión 16.8. Desde entonces, toda la arquitectura de react se ha transformado en una serie de "Hooks" que permiten implementar la mayoria de los patrones de programacion mas importantes. -El useReducer es una propuesta de React para separar la logica de la vista en tus componentes. Hay otras soluciones como Redux, Flux, Global Context, etc. Sin embargo, el useReducer es sencillo de usar y mantiene un alcance local sobre los datos, es decir, a pesar de reusar las funciones y codigo de los componentes, no se compartiran los datos entre sí. -## Ejemplo de useReducer - -Este es el ejemplo más sencillo de useReducer: +El useReducer es una nueva propuesta de React para separar la logica de la vista en tus componentes. Hay otras soluciones como Redux, Flux, Global Context, etc. Sin embargo, el useReducer se ha vuelto popular por ser sencillo de usar y mantener un alcance local sobre los datos, es decir, a pesar de reusar las funciones y codigo de los componentes, no se compartiran los datos entre sí. -```react - const intitialCounter = () => ({counter: 0}); - const [state, dispatch] = useReducer(counterReducer, intitialCounter()); -``` +> Separar los datos de los componentes ayudar a prevenir errores comunes y reutilizar la información y la lógica en la aplicacion. -El hook `useReducer` recibe como primer parámetro una función que define el `reducer`, y va a retornar un arreglo de dos valores que representan al nuevo estado (`state`) y el dispatcher: El objeto que permite ejecutar las acciones/funciones de la lógica del reducer (`actions`). Como segundo parámetro se debe pasar una función que retorne un objeto con los valores iniciales del estado. - -> El segundo valor del arreglo que deveulve el useReducer se llama "dispacher" y no "actions" porque es necesario tener un "despachador" de acciones como intermediario para evitar conflictos en los datos. +## Ejemplo de useReducer -A su vez la función reducer (en este ejemplo se llama `counterReducer`) se define con 2 parámetros: El `state` que contiene los datos del reducer, y un objeto `"actions"` que se usa para identificar las acciones que podemos ejecutar para manipular el state. +El primer paso es declarar una función reducer (en este ejemplo se llama `counterReducer`) se define con 2 parámetros: El `state` que contiene los datos del reducer, y un objeto `actions` que se usa para identificar las acciones que podemos ejecutar para manipular el state. -```react +```javascript function counterReducer(state , action = {}) { // Aquí el reducer recibe el estado actual // luego ejecuta las acciones @@ -38,21 +30,31 @@ function counterReducer(state , action = {}) { } ``` -Esta función reducer se va a ejecutar en cada llamado de acción y deberá retornar una nueva versión del estado que reemplaza por completo la anterior al terminar su ejecución, por lo que hay que ser cuidadoso y sólo alterar lo que necesitamos y retornar siempre los demás valores del estado utilizando la desestructuracion (js destructuring) 🤓. +Esta función reducer se encarga de mutar (o "modificar") el estado de tu componente en funcion de los tipos de acciónes predefinidas, y deberá retornar una nueva versión del estado que reemplaza por completo la anterior al terminar su ejecución, por lo que hay que ser cuidadoso y sólo alterar lo que necesitamos y retornar siempre los demás valores del estado utilizando la desestructuracion (js destructuring) 🤓. -👍**SI** ```javascript -return { ...state, counter: state.counter + 1 } +function counterReducer(state , action = {}) { + // Hagas lo que hagas, siempre retorna un nuevo estado + + //👍**SI** + return { ...state, counter: state.counter + 1 } + + //🚫**NO** + //return { counter: state.counter + 1 } +} ``` -🚫**NO** +Esta funcion se utiliza como primer parámetro del hook `useReducer`. Como segundo parámetro se debe pasar una función que retorne un objeto con los valores iniciales del estado. + +El llamado al hook retorna un arreglo de dos valores que representan al nuevo estado (`state`) y el dispatcher: El objeto que llama la ejecución de las acciones de la lógica del reducer (`actions`). ```javascript -return { counter: state.counter + 1 } + const intitialCounter = () => ({counter: 0}); + const [state, dispatch] = useReducer(counterReducer, intitialCounter()); ``` -Dentro del reducer, el objeto `actions` contiene una propiedad `type` que nos indica que acción ha sido invocada, y podremos escribir la lógica basado en ello. +Dentro del reducer, el objeto `actions` contiene una propiedad `type` que nos indica qué acción ha sido invocada, y podremos escribir la lógica mutar el estado por completo. ```javascript export default function counterReducer(state, action = {}) { @@ -69,16 +71,18 @@ export default function counterReducer(state, action = {}) { return { ...state, counter: 0 }; default: // En caso no tener ningún tipo se retorna el estado sin alterar - return state; + throw Error("No se encuentra la accion especificada") } } ``` +Ademas de las acciones especificadas, se coloca un caso `default` que se ejecuta cuando el tipo de accion no esta definido, para lo cual se arroja un error que interrumpe la aplicación. Esto puede parecer un poco extremo, pero es mejor tener un error visible y depurarlo, que tener una aplicacion sin errores(🐞bugs) pero que no funciona como deberia. + Ya con esto podemos tener tanto las funciones `counterReducer` e `intitialCounter` exportadas en un archivo, para ser utilizadas por cualquier otro componente 👌. ## Porque usar useReducer -Estamos acostumbrados a percibir los componentes como la unidad que agrupa la vista y la lógica para su funcionamiento. Por ejemplo: En el siguiente código hay un componente `Counter` que tiene el HTML para definir como debería verse un contador de números y tambien existe la logica de como deberia sumar una unidad cada vez que se presione el botón "+1" +Estamos acostumbrados a percibir los componentes como la unidad que agrupa la vista y la lógica para su funcionamiento. Por ejemplo: En el siguiente código hay un componente `Counter` que tiene el HTML para definir como debería verse un contador de números y tambien existe la logica de como sumar una unidad cada vez que se presione el botón "+1" ```jsx export default function Counter() { @@ -102,7 +106,7 @@ export default function Counter() { Pero ¿Qué pasa si necesitamos reutilizar sólo la lógica en otros componentes? Podríamos [hablar de estados centralizados](https://4geeks.com/es/lesson/context-api-es), pero ¿Qué pasa si sólo quiero reutilizar la lógica y que cada componente tenga un estado propio? Una solución poco práctica seria copiar y pegar, o exportar las funciones desde un archivo aparte y buscar alguna manera de hacerlas trabajar con el estado de cada componente 😰. Eso no suena conveniente... -La solución a este problema es `useReducer`, que como dice su nombre, su función es **reducir** un estado y su lógica a una unidad reutilizable, permitiendo que esta se pueda exportar desde un archivo a los componentes que lo necesiten 💪. Este reducer va a cohexistir con el resto de la sintaxis típica de un componente React, puedes [aprender más aquí](https://4geeks.com/es/lesson/making-react-components-es). +Una solución a este problema es `useReducer`, que como dice su nombre, su función es **reducir** un estado y su lógica a una unidad reutilizable, permitiendo que esta se pueda exportar desde un archivo a los componentes que lo necesiten 💪. Este reducer va a cohexistir con el resto de la sintaxis típica de un componente React, puedes [aprender más aquí](https://4geeks.com/es/lesson/making-react-components-es). ## Migrando de useState a useReducer @@ -112,7 +116,7 @@ En este ejemplo tenemos un contador que no solamente suma de 1 en 1, sino tambi Para realizar todas estas acciones se necesitan funciones para cada una de ellas, ademas del estado en si. Para eso usaremos el clasico hook `useState`, [aprende mas aquí](https://4geeks.com/es/lesson/react-hooks-explained-es). -```react +```jsx export default function CounterUsingState() { const [counter, setCounter] = useState(0); const increment = () => setCounter(counter + 1); @@ -139,7 +143,7 @@ export default function CounterUsingState() { Esto funciona perfecto, pero para hacer la lógica reutilizable y moverlo a otro archivo, lo convertiremos en un reducer: -```react +```javascript // counterReducer.js export const intitialCounter = () => ({ counter: 0 @@ -165,7 +169,7 @@ export default function counterReducer(state, action = {}) { Ahora desde el componente importamos y hacemos uso del reducer: -```react +```jsx import React, { useReducer } from "react"; import counterReducer, { intitialCounter } from "./counterReducer"; diff --git a/src/content/lesson/optimize-react-components-usereducer.md b/src/content/lesson/optimize-react-components-usereducer.md index 3b014106c..2421513f4 100644 --- a/src/content/lesson/optimize-react-components-usereducer.md +++ b/src/content/lesson/optimize-react-components-usereducer.md @@ -12,41 +12,45 @@ status: "draft" ## What is the useReducer hook? -The hooks were launched on version 16.8 of React. Since then all the architecture of react has transformed into a series of hooks that allow the implementation of most of the most important coding design patterns. +The hooks were launched on version 16.8 of React. Since then all the architecture of react has transformed into a series of hooks that allow the implementation of most of the most important coding design patterns. + useReducer is a proposal from React to separate the logic from the view of your components. There are other solutions like Redux, Flux, Global Context, etc; however, useReducer is easy to use and keeps the data in a local scope, which means that even when the components are reusing the functions, they don't share data. ## Example of a useReducer -The `useReducer` hook receives as the first parameter a function that defines the `reducer` and will return an array of two values that represents the state of the reducer (`state`) and the object that allows dispatching the actions that perform the logic of the reducer (`actions`). As a second parameter, it receives a function that returns an object with the initial values of the state. - -```javascript - const intitialCounter = () => ({counter: 0}); - const [state, dispatch] = useReducer(counterReducer, intitialCounter()); -``` - -At the same time, the reducer function itself is defined with 2 parameters: The `state` that has all the data of the reducer, and an object that is used to identify the actions that must be performed inside it (which we'll call `actions`). +The first step is to declare a reducer function wich is defined with 2 parameters: The `state` that has all the data of the reducer, and an `actions` object that is used to identify the actions can be performed to manipulate the state. ```javascript function counterReducer(state , action = {}) { // Here the reducer receives the state and execute the actions + // at last, it returns a new state. } ``` -This reducer function will be executed on every action call and it must return the new version of the state which replaces entirely the previous one at the end of the execution, which is why you must be careful to only write what you need and keep all the other values intact by using destructuring 🤓. +This reducer function is in charge of mutate (modify) the state of your component according to the predefined action types, and it must return the new version of the state which replaces entirely the previous one at the end of the execution, which is why you must be careful to only write what you need and keep all the other values intact by using destructuring 🤓. -👍**YES** ```javascript -return { ...state, counter: state.counter + 1 } +function counterReducer(state , action = {}) { + // Whatever you do, always return a new state + //👍**YES** + return { ...state, counter: state.counter + 1 } + + //🚫**NO** + //return { counter: state.counter + 1 } +} ``` -🚫**NO** +This function is meant to be used as the first parameter of the `useReducer` hoook. As a second parameter, it receives a function that returns an object with the initial values of the state. + +The hook call returns an array of two values that represents the state (`state`) and the dispatcher: The object that call the executions of actions that perform the logic of the reducer (`actions`). ```javascript -return { counter: state.counter + 1 } + const intitialCounter = () => ({counter: 0}); + const [state, dispatch] = useReducer(counterReducer, intitialCounter()); ``` -Inside the reducer, the object `actions` contain the property `type` that indicates to us which action has been invoked, and we can write the logic based on it. +Inside the reducer, the object `actions` contain the property `type` that indicates which action has been invoked, and we can write the logic to mutate the state entirely. ```javascript export default function counterReducer(state, action = {}) { @@ -72,6 +76,28 @@ With this, we can have the functions `counterReducer` and `intitialCounter` expo ## Why use useReducer? +We are used to perceive the components as the unit that groups the view and the logic for its operation. For example: In the following code there is a `Counter` component that has the HTML to define how a counter of numbers should look like and there is also the logic of how it adds a unit each time the "+1" button is pressed. + +```jsx +export default function Counter() { + + // Logic ⬇️ + const [counter, setCounter] = useState(0); + const increment = () => setCounter(counter + 1); + + // View ⬇️ + return ( +
+

State counter

+

{counter}

+
+ +
+
+ ); +} +``` + What if we need to reuse only the logic in other components? We could consider [centralized states](https://4geeks.com/lesson/context-api), but what if I want to reuse only the logic while leaving every component with its own state? The janky solution would be copying the functions to another file, exporting them from there, and figuring out a way to make them work with every single state component 😰. It doesn't sound convenient... One solution for this issue is `useReducer`, which as its name suggests **reduces** the state and the logic to a single reusable unit, allowing it to be exported from a file to every component that needs it 💪. This reducer will coexist with the rest of the ordinary component syntax, you can [learn more here](https://4geeks.com/lesson/making-react-components). From fc7a0c993b36d9f79724a40007fcedc813f0bf8c Mon Sep 17 00:00:00 2001 From: Arnaldo Perez Date: Thu, 9 May 2024 16:18:36 -0400 Subject: [PATCH 6/6] review useReducer lesson --- .../lesson/database-normalization.es.md | 151 ++++++++++++++++++ ...optimize-react-components-usereducer.es.md | 62 +++---- .../optimize-react-components-usereducer.md | 56 +++++-- .../lesson/react-design-patterns.es.md | 18 +-- src/content/lesson/react-design-patterns.md | 6 +- 5 files changed, 237 insertions(+), 56 deletions(-) create mode 100644 src/content/lesson/database-normalization.es.md diff --git a/src/content/lesson/database-normalization.es.md b/src/content/lesson/database-normalization.es.md new file mode 100644 index 000000000..31201a6c8 --- /dev/null +++ b/src/content/lesson/database-normalization.es.md @@ -0,0 +1,151 @@ +## Conceptos básicos + +Cuando hablamos de bases de datos relacionales La principal ventaja que se nos viene a la mente es la integridad de los datos estas bases de datos permiten distribuir la información en Tablas distintas para agrupar información Según sea pertinente y crear relaciones entre las tablas para asociar la información. sin embargo para mantener la integridad es necesario cumplir ciertos estándares a la hora de diseñar nuestras tablas Necesitamos que la estructura sea pertinente a los datos que queremos almacenar y que garantice la integridad de la información así como su consistencia y evite Tener información redundante innecesaria. + +Para ello existe la normalización de base de datos. se trata de cinco formas normales que de cumplirlas tu base de datos garantizará la integridad de la información y la optimización a la hora de hacer consultas. las formas cuatro y cinco generalmente se contemplan para escenarios más avanzados y de mayor complejidad, para la mayoría de los casos bastará con cumplir las tres primeras formas normales que cubriremos a continuación en este artículo. + +Antes de hablar de las formas normales debemos manejar algunos conceptos fundamentales. + +El primer concepto es entidad, se trata de una abstracción de un objeto de la realidad o de un proceso de la organización cuyos datos deben ser almacenados en la base de datos de manera agrupada y correlacionada. + +El segundo es llave primaria, se trata de un atributo o columna que sirve para identificar de manera inequívoca a una entidad dentro de una tabla. + + +## Primera forma Normal - 1NF + +Para que una tabla cumpla con la primera forma normal debe cumplir los siguientes parámetros: + + + +* Cada celda debe tener un único valor +* Debe haber una llave primaria para identificar cada entidad +* No debe haber filas o columnas duplicadas + +Si por ejemplo tenemos una tabla de pedidos de productos de la siguiente forma: + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Pedido + Detalle + Cliente +
1 + 2 Zapatos + Pedro +
1 + 3 Pantalones + Pedro +
2 + 1 Bolso + María +
3 + 1 Camisa + Ana +
+ + +Podemos notar que la columna detalle contiene dos datos importantes para el pedido la cantidad y la información del producto. de la misma forma podemos notar como si bien Podemos identificar el pedido con el ID no ocurre lo mismo en el caso de los productos y del cliente puesto que solo tenemos un nombre que No necesariamente es único para cada uno y puede ser repetido. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Pedido + IdProducto + NombreProducto + Cantidad + IdCliente + Cliente +
1 + 1z + Zapatos + 2 + 1 + Pedro +
1 + 3P + Pantalones + 3 + 1 + Pedro +
2 + 2B + Bolso + 1 + 2 + María +
3 + 2Z + Zapatos + 1 + 3 + Ana +
+ + +Ahora podemos ver cómo no solo el pedido se puede identificar con su ID sino que también Contamos con ideas para el producto y el cliente de manera que cada una de estas entidades pueda ser identificada. + + +## Segunda forma normal - 2NF. diff --git a/src/content/lesson/optimize-react-components-usereducer.es.md b/src/content/lesson/optimize-react-components-usereducer.es.md index c3b3c3512..eb40cf026 100644 --- a/src/content/lesson/optimize-react-components-usereducer.es.md +++ b/src/content/lesson/optimize-react-components-usereducer.es.md @@ -1,5 +1,5 @@ --- -title: "Qué es y como usar el hook useReducer en React.js" +title: "¿Qué es y cómo usar el hook useReducer en React.js" subtitle: "Aprende a usar el hook useReducer en React.js y cómo funciona, comparalo con otras alternativas como redux, flux, entre otras." cover: "https://www.desktopbackground.org/p/2013/09/13/637935_nasa-wallpapers_1600x1200_h.jpg" textColor: "white" @@ -12,25 +12,17 @@ status: "draft" ## Que es el useReducer Los hooks empezaron a existir en react desde la versión 16.8. -Desde entonces, toda la arquitectura de react se ha transformado en una serie de "Hooks" que permiten implementar la mayoria de los patrones de programacion mas importantes. -El useReducer es una propuesta de React para separar la logica de la vista en tus componentes. Hay otras soluciones como Redux, Flux, Global Context, etc. Sin embargo, el useReducer es sencillo de usar y mantiene un alcance local sobre los datos, es decir, a pesar de reusar las funciones y codigo de los componentes, no se compartiran los datos entre sí. +Desde entonces, toda la arquitectura de react se ha transformado en una serie de "Hooks" que permiten implementar la mayoría de los patrones de programación mas importantes. -## Ejemplo de useReducer - -Este es el ejemplo más sencillo de useReducer: +El useReducer es una nueva propuesta de React para separar la logica de la vista en tus componentes. Hay otras soluciones como Redux, Flux, Global Context, etc. Sin embargo, el useReducer se ha vuelto popular por ser sencillo de usar y mantener un alcance local sobre los datos, es decir, a pesar de reutilizar las funciones y código de los componentes, no se compartirán los datos entre sí. -```react - const intitialCounter = () => ({counter: 0}); - const [state, dispatch] = useReducer(counterReducer, intitialCounter()); -``` +> Separar los datos de los componentes ayudar a prevenir errores comunes y reutilizar la información y la lógica en la aplicación. -El hook `useReducer` recibe como primer parámetro una función que define el `reducer`, y va a retornar un arreglo de dos valores que representan al nuevo estado (`state`) y el dispatcher: El objeto que permite ejecutar las acciones/funciones de la lógica del reducer (`actions`). Como segundo parámetro se debe pasar una función que retorne un objeto con los valores iniciales del estado. - -> El segundo valor del arreglo que deveulve el useReducer se llama "dispacher" y no "actions" porque es necesario tener un "despachador" de acciones como intermediario para evitar conflictos en los datos. +## Ejemplo de useReducer -A su vez la función reducer (en este ejemplo se llama `counterReducer`) se define con 2 parámetros: El `state` que contiene los datos del reducer, y un objeto `"actions"` que se usa para identificar las acciones que podemos ejecutar para manipular el state. +El primer paso es declarar una función reducer (en este ejemplo se llama `counterReducer`) se define con 2 parámetros: El `state` que contiene los datos del reducer, y un objeto `actions` que se usa para identificar las acciones que podemos ejecutar para manipular el state. -```react +```javascript function counterReducer(state , action = {}) { // Aquí el reducer recibe el estado actual // luego ejecuta las acciones @@ -38,21 +30,31 @@ function counterReducer(state , action = {}) { } ``` -Esta función reducer se va a ejecutar en cada llamado de acción y deberá retornar una nueva versión del estado que reemplaza por completo la anterior al terminar su ejecución, por lo que hay que ser cuidadoso y sólo alterar lo que necesitamos y retornar siempre los demás valores del estado utilizando la desestructuracion (js destructuring) 🤓. +Esta función reducer se encarga de mutar (o "modificar") el estado de tu componente en función de los tipos de acciones predefinidas, y deberá retornar una nueva versión del estado que reemplaza por completo la anterior al terminar su ejecución, por lo que hay que ser cuidadoso y sólo alterar lo que necesitamos y retornar siempre los demás valores del estado utilizando la desestructuracion (js destructuring) 🤓. -👍**SI** ```javascript -return { ...state, counter: state.counter + 1 } +function counterReducer(state , action = {}) { + // Hagas lo que hagas, siempre retorna un nuevo estado + + //👍**SI** + return { ...state, counter: state.counter + 1 } + + //🚫**NO** + //return { counter: state.counter + 1 } +} ``` -🚫**NO** +Esta función se utiliza como primer parámetro del hook `useReducer`. Como segundo parámetro se debe pasar una función que retorne un objeto con los valores iniciales del estado. + +El llamado al hook retorna un arreglo de dos valores que representan al nuevo estado (`state`) y el dispatcher: El objeto que llama la ejecución de las acciones de la lógica del reducer (`actions`). ```javascript -return { counter: state.counter + 1 } + const intitialCounter = () => ({counter: 0}); + const [state, dispatch] = useReducer(counterReducer, intitialCounter()); ``` -Dentro del reducer, el objeto `actions` contiene una propiedad `type` que nos indica que acción ha sido invocada, y podremos escribir la lógica basado en ello. +Dentro del reducer, el objeto `actions` contiene una propiedad `type` que nos indica qué acción ha sido invocada, y podremos escribir la lógica mutar el estado por completo. ```javascript export default function counterReducer(state, action = {}) { @@ -69,21 +71,23 @@ export default function counterReducer(state, action = {}) { return { ...state, counter: 0 }; default: // En caso no tener ningún tipo se retorna el estado sin alterar - return state; + throw Error("No se encuentra la acción especificada") } } ``` +Ademas de las acciones especificadas, se coloca un caso `default` que se ejecuta cuando el tipo de acción no esta definido, para lo cual se arroja un error que interrumpe la aplicación. Esto puede parecer un poco extremo, pero es mejor tener un error visible y depurarlo, que tener una aplicación sin errores(🐞bugs) pero que no funciona como debería. + Ya con esto podemos tener tanto las funciones `counterReducer` e `intitialCounter` exportadas en un archivo, para ser utilizadas por cualquier otro componente 👌. ## Porque usar useReducer -Estamos acostumbrados a percibir los componentes como la unidad que agrupa la vista y la lógica para su funcionamiento. Por ejemplo: En el siguiente código hay un componente `Counter` que tiene el HTML para definir como debería verse un contador de números y tambien existe la logica de como deberia sumar una unidad cada vez que se presione el botón "+1" +Estamos acostumbrados a percibir los componentes como la unidad que agrupa la vista y la lógica para su funcionamiento. Por ejemplo: En el siguiente código hay un componente `Counter` que tiene el HTML para definir como debería verse un contador de números y también existe la lógica de como sumar una unidad cada vez que se presione el botón "+1" ```jsx export default function Counter() { - // Logica ⬇️ + // Lógica ⬇️ const [counter, setCounter] = useState(0); const increment = () => setCounter(counter + 1); @@ -102,7 +106,7 @@ export default function Counter() { Pero ¿Qué pasa si necesitamos reutilizar sólo la lógica en otros componentes? Podríamos [hablar de estados centralizados](https://4geeks.com/es/lesson/context-api-es), pero ¿Qué pasa si sólo quiero reutilizar la lógica y que cada componente tenga un estado propio? Una solución poco práctica seria copiar y pegar, o exportar las funciones desde un archivo aparte y buscar alguna manera de hacerlas trabajar con el estado de cada componente 😰. Eso no suena conveniente... -La solución a este problema es `useReducer`, que como dice su nombre, su función es **reducir** un estado y su lógica a una unidad reutilizable, permitiendo que esta se pueda exportar desde un archivo a los componentes que lo necesiten 💪. Este reducer va a cohexistir con el resto de la sintaxis típica de un componente React, puedes [aprender más aquí](https://4geeks.com/es/lesson/making-react-components-es). +Una solución a este problema es `useReducer`, que como dice su nombre, su función es **reducir** un estado y su lógica a una unidad reutilizable, permitiendo que esta se pueda exportar desde un archivo a los componentes que lo necesiten 💪. Este reducer va a cohexistir con el resto de la sintaxis típica de un componente React, puedes [aprender más aquí](https://4geeks.com/es/lesson/making-react-components-es). ## Migrando de useState a useReducer @@ -110,9 +114,9 @@ En este ejemplo tenemos un contador que no solamente suma de 1 en 1, sino tambi ![react counter using state](https://breathecode.herokuapp.com/v1/media/file/state-counter-png?width=200) -Para realizar todas estas acciones se necesitan funciones para cada una de ellas, ademas del estado en si. Para eso usaremos el clasico hook `useState`, [aprende mas aquí](https://4geeks.com/es/lesson/react-hooks-explained-es). +Para realizar todas estas acciones se necesitan funciones para cada una de ellas, ademas del estado en si. Para eso usaremos el clásico hook `useState`, [aprende mas aquí](https://4geeks.com/es/lesson/react-hooks-explained-es). -```react +```jsx export default function CounterUsingState() { const [counter, setCounter] = useState(0); const increment = () => setCounter(counter + 1); @@ -139,7 +143,7 @@ export default function CounterUsingState() { Esto funciona perfecto, pero para hacer la lógica reutilizable y moverlo a otro archivo, lo convertiremos en un reducer: -```react +```javascript // counterReducer.js export const intitialCounter = () => ({ counter: 0 @@ -165,7 +169,7 @@ export default function counterReducer(state, action = {}) { Ahora desde el componente importamos y hacemos uso del reducer: -```react +```jsx import React, { useReducer } from "react"; import counterReducer, { intitialCounter } from "./counterReducer"; diff --git a/src/content/lesson/optimize-react-components-usereducer.md b/src/content/lesson/optimize-react-components-usereducer.md index 3b014106c..2421513f4 100644 --- a/src/content/lesson/optimize-react-components-usereducer.md +++ b/src/content/lesson/optimize-react-components-usereducer.md @@ -12,41 +12,45 @@ status: "draft" ## What is the useReducer hook? -The hooks were launched on version 16.8 of React. Since then all the architecture of react has transformed into a series of hooks that allow the implementation of most of the most important coding design patterns. +The hooks were launched on version 16.8 of React. Since then all the architecture of react has transformed into a series of hooks that allow the implementation of most of the most important coding design patterns. + useReducer is a proposal from React to separate the logic from the view of your components. There are other solutions like Redux, Flux, Global Context, etc; however, useReducer is easy to use and keeps the data in a local scope, which means that even when the components are reusing the functions, they don't share data. ## Example of a useReducer -The `useReducer` hook receives as the first parameter a function that defines the `reducer` and will return an array of two values that represents the state of the reducer (`state`) and the object that allows dispatching the actions that perform the logic of the reducer (`actions`). As a second parameter, it receives a function that returns an object with the initial values of the state. - -```javascript - const intitialCounter = () => ({counter: 0}); - const [state, dispatch] = useReducer(counterReducer, intitialCounter()); -``` - -At the same time, the reducer function itself is defined with 2 parameters: The `state` that has all the data of the reducer, and an object that is used to identify the actions that must be performed inside it (which we'll call `actions`). +The first step is to declare a reducer function wich is defined with 2 parameters: The `state` that has all the data of the reducer, and an `actions` object that is used to identify the actions can be performed to manipulate the state. ```javascript function counterReducer(state , action = {}) { // Here the reducer receives the state and execute the actions + // at last, it returns a new state. } ``` -This reducer function will be executed on every action call and it must return the new version of the state which replaces entirely the previous one at the end of the execution, which is why you must be careful to only write what you need and keep all the other values intact by using destructuring 🤓. +This reducer function is in charge of mutate (modify) the state of your component according to the predefined action types, and it must return the new version of the state which replaces entirely the previous one at the end of the execution, which is why you must be careful to only write what you need and keep all the other values intact by using destructuring 🤓. -👍**YES** ```javascript -return { ...state, counter: state.counter + 1 } +function counterReducer(state , action = {}) { + // Whatever you do, always return a new state + //👍**YES** + return { ...state, counter: state.counter + 1 } + + //🚫**NO** + //return { counter: state.counter + 1 } +} ``` -🚫**NO** +This function is meant to be used as the first parameter of the `useReducer` hoook. As a second parameter, it receives a function that returns an object with the initial values of the state. + +The hook call returns an array of two values that represents the state (`state`) and the dispatcher: The object that call the executions of actions that perform the logic of the reducer (`actions`). ```javascript -return { counter: state.counter + 1 } + const intitialCounter = () => ({counter: 0}); + const [state, dispatch] = useReducer(counterReducer, intitialCounter()); ``` -Inside the reducer, the object `actions` contain the property `type` that indicates to us which action has been invoked, and we can write the logic based on it. +Inside the reducer, the object `actions` contain the property `type` that indicates which action has been invoked, and we can write the logic to mutate the state entirely. ```javascript export default function counterReducer(state, action = {}) { @@ -72,6 +76,28 @@ With this, we can have the functions `counterReducer` and `intitialCounter` expo ## Why use useReducer? +We are used to perceive the components as the unit that groups the view and the logic for its operation. For example: In the following code there is a `Counter` component that has the HTML to define how a counter of numbers should look like and there is also the logic of how it adds a unit each time the "+1" button is pressed. + +```jsx +export default function Counter() { + + // Logic ⬇️ + const [counter, setCounter] = useState(0); + const increment = () => setCounter(counter + 1); + + // View ⬇️ + return ( +
+

State counter

+

{counter}

+
+ +
+
+ ); +} +``` + What if we need to reuse only the logic in other components? We could consider [centralized states](https://4geeks.com/lesson/context-api), but what if I want to reuse only the logic while leaving every component with its own state? The janky solution would be copying the functions to another file, exporting them from there, and figuring out a way to make them work with every single state component 😰. It doesn't sound convenient... One solution for this issue is `useReducer`, which as its name suggests **reduces** the state and the logic to a single reusable unit, allowing it to be exported from a file to every component that needs it 💪. This reducer will coexist with the rest of the ordinary component syntax, you can [learn more here](https://4geeks.com/lesson/making-react-components). diff --git a/src/content/lesson/react-design-patterns.es.md b/src/content/lesson/react-design-patterns.es.md index 14a37dc68..cac45fd7d 100644 --- a/src/content/lesson/react-design-patterns.es.md +++ b/src/content/lesson/react-design-patterns.es.md @@ -1,6 +1,6 @@ ## ¿Que son patrones de diseño? -La programación se trata de escribir instrucciones para ser interpretadas por una maquina, lo que nos lleva en muchos casos a que existan muchas formas de solucionar un mismo problema. Aun asi hay asuntos comunes que se deben considerar a la hora de hacer crecer un sistema o lograr que tenga un buen desempeño si tiene una gran concurrencia, ahi los patrones de diseño nos ayudan a dar solución a estos escenarios. +La programación se trata de escribir instrucciones para ser interpretadas por una maquina, lo que nos lleva en muchos casos a que existan varias formas de solucionar un mismo problema. Aun asi hay asuntos comunes que se deben considerar a la hora de hacer crecer un sistema o lograr que tenga un buen desempeño si tiene una gran concurrencia, ahi los patrones de diseño nos ayudan a dar solución a estos escenarios. > Los patrones de diseño son estrategias para solucionar problemas comunes en la programación. Algunos solucionan problemas de reutilización de código, otros problemas de escalabilidad o eficiencia. No se trata de librerías o frameworks específicos, son mas bien formas de utilizar las herramientas que te ofrece una determinada tecnología, para evitar problemas que ya son bien conocidos y cuyas soluciones ya han sido probadas. @@ -17,7 +17,7 @@ Algunas librerías implementan este patrón por defecto, como por ejemplo React Claro que también puedes crear tus propios contextos con lo que necesites, por ejemplo puedes crear un contexto que sirva para cambiar el diseño de tu aplicación de un modo claro a un modo oscuro, veamos como hacerlo: -```react +``` jsx // ThemeProvider.jsx import React, { createContext, useContext, useState } from "react"; @@ -46,7 +46,7 @@ export function ThemeProvider({ children }) { Luego de esto solo queda envolver nuestra aplicación en el proveedor y empezar a usar el contexto en nuestros componentes. -```react +```jsx // index.jsx import React from "react"; import ReactDOM from "react-dom/client"; @@ -63,7 +63,7 @@ ReactDOM.createRoot(document.getElementById("root")).render( ); ``` -```react +```jsx // App.jsx import "./App.css"; // Importamos el contexto de nuestro tema @@ -90,7 +90,7 @@ Este patrón plantea la creación de componentes que estén diseñados para cont En este ejemplo tenemos un componente de tarjeta (Card) de bootstrap que tiene una funcionalidad básica, pero que implementa el patrón HOC para que recibir otros componentes como cuerpo de dicha tarjeta. Esto permite tener componentes de tarjeta similares, que comparten funcionalidades comunes, pero que tienen una estructura propia para el contenido. -```react +```jsx // Card.jsx export default function wrapCard(BodyComponent) { const CardWrapper = (props) => { @@ -118,7 +118,7 @@ export default function wrapCard(BodyComponent) { A la hora de crear el componente para el cuerpo se debe exportar llamando a la función que lo va a envolver en el componente de nivel superior. -```react +```jsx // Character.jsx import wrapCard from "./Card"; @@ -148,7 +148,7 @@ Este patrón plantea la integración de componentes que están hechos para traba Si bien los componentes hijos se declaran como cualquier otro componente, se suelen exportar como miembros del componente principal, para que en implementación sea mas notoria su integración. -```react +```jsx // Contexto para el conjunto de componentes const SelectContext = createContext(); @@ -166,7 +166,7 @@ export default Select; Para el ejemplo crearemos un selector de opciones para un formulario. El componente padre será `