Patrones de Diseño: Patrón de Proveedor (Página 4)

En algunos casos, queremos que los datos estén disponibles para muchos (si no todos) los componentes de una aplicación. Aunque podemos pasar datos a los componentes usando props , esto puede resultar difícil si casi todos los componentes de su aplicación necesitan acceder al valor de los accesorios.

A menudo terminamos con algo llamado perforación de accesorios , que es el caso cuando pasamos accesorios muy abajo en el árbol de componentes. Refactorizar el código que depende de los accesorios se vuelve casi imposible y saber de dónde provienen ciertos datos es difícil.

Digamos que tenemos un App componente que contiene ciertos datos. Más abajo en el árbol de componentes, tenemos un componente ListItem y Header un Text componente que necesita estos datos. Para llevar estos datos a estos componentes, tendríamos que pasarlos a través de múltiples capas de componentes.

En nuestro código base, se vería así:

function App() {
const data = { ... }
return (
<div>
<SideBar data={data} />
<Content data={data} />
</div>
)
}
const SideBar = ({ data }) => <List data={data} />
const List = ({ data }) => <ListItem data={data} />
const ListItem = ({ data }) => <span>{data.listItem}</span>
const Content = ({ data }) => (
<div>
<Header data={data} />
<Block data={data} />
</div>
)
const Header = ({ data }) => <div>{data.title}</div>
const Block = ({ data }) => <Text data={data} />
const Text = ({ data }) => <h1>{data.text}</h1>

Pasar accesorios de esta manera puede resultar bastante complicado. Si queremos cambiar el nombre del data accesorio en el futuro, tendríamos que cambiarle el nombre en todos los componentes. Cuanto más grande sea su aplicación, más complicada puede ser la perforación de hélice.

It would be optimal if we could skip all the layers of components that don’t need to use this data. We need to have something that gives the components that need access to the value of data direct access to it, without relying on prop drilling.

This is where the Provider Pattern can help us out! With the Provider Pattern, we can make data available to multiple components. Rather than passing that data down each layer through props, we can wrap all components in a Provider . A Provider is a higher order component provided to us by the Context object. We can create a Context object, using the createContext method that React provides for us.

The Provider receives a value prop, which contains the data that we want to pass down. All components that are wrapped within this provider have access to the value of the value prop.

const DataContext = React.createContext()
function App() {
const data = { ... }
return (
<div>
<DataContext.Provider value={data}>
<SideBar />
<Content />
</DataContext.Provider>
</div>
)
}

¡Ya no tenemos que pasar manualmente el data accesorio a cada componente! Entonces, ¿cómo pueden los componentes y ListItem acceder al valor de ? Header``Text``data

Cada componente puede obtener acceso a data , mediante el uso del useContext gancho. Este gancho recibe el contexto al que data tiene referencia, DataContext en este caso. El useContext gancho nos permite leer y escribir datos en el objeto de contexto.

const DataContext = React.createContext();
function App() {
const data = { ... }
return (
<div>
<SideBar />
<Content />
</div>
)
}
const SideBar = () => <List />
const List = () => <ListItem />
const Content = () => <div><Header /><Block /></div>
function ListItem() {
const { data } = React.useContext(DataContext);
return <span>{data.listItem}</span>;
}
function Text() {
const { data } = React.useContext(DataContext);
return <h1>{data.text}</h1>;
}
function Header() {
const { data } = React.useContext(DataContext);
return <div>{data.title}</div>;
}

Los componentes que no utilizan el data valor no tendrán que lidiar con data ningún problema. Ya no tenemos que preocuparnos por pasar accesorios a varios niveles a través de componentes que no necesitan el valor de los accesorios, lo que hace que la refactorización sea mucho más fácil.

El patrón Proveedor es muy útil para compartir datos globales. Un caso de uso común para el patrón de proveedor es compartir el estado de la interfaz de usuario de un tema con muchos componentes.


Queremos que el usuario pueda cambiar entre el modo claro y el modo oscuro alternando el interruptor. Cuando el usuario cambia del modo oscuro al modo claro y viceversa, ¡el color de fondo y el color del texto deberían cambiar! En lugar de pasar el valor del tema actual a cada componente, podemos envolver los componentes en un ThemeProvider y pasar los colores del tema actual al proveedor.

export const ThemeContext = React.createContext();
const themes = {
light: {
background: "#fff",
color: "#000",
},
dark: {
background: "#171717",
color: "#fff",
},
};
export default function App() {
const [theme, setTheme] = useState("dark");
function toggleTheme() {
setTheme(theme === "light" ? "dark" : "light");
}
const providerValue = {
theme: themes[theme],
toggleTheme,
};
return (
<div className={`App theme-${theme}`}>
<ThemeContext.Provider value={providerValue}>
<Toggle />
<List />
</ThemeContext.Provider>
</div>
);
}

Dado que los componentes Toggle y List están incluidos dentro del ThemeContext proveedor, tenemos acceso a los valores theme y toggleTheme se pasan como value al proveedor.

Dentro del Toggle componente, podemos usar la toggleTheme función para actualizar el tema en consecuencia.

import React, { useContext } from "react";
import { ThemeContext } from "./App";
export default function Toggle() {
const theme = useContext(ThemeContext);
return (
<label className="switch">
<input type="checkbox" onClick={theme.toggleTheme} />
<span className="slider round" />
</label>
);
}

Al List componente en sí no le importa el valor actual del tema. Sin embargo, ¡los ListItem componentes sí! Podemos usar el theme contexto directamente dentro del ListItem .

import React, { useContext } from "react";
import { ThemeContext } from "./App";
export default function TextBox() {
const theme = useContext(ThemeContext);
return <li style={theme.theme}>...</li>;
}

¡Perfecto! No tuvimos que transmitir ningún dato a componentes a los que no les importaba el valor actual del tema.

Hands

Podemos crear un gancho para proporcionar contexto a los componentes. En lugar de tener que importar useContext el contexto en cada componente, podemos usar un enlace que devuelva el contexto que necesitamos.

function useThemeContext() {
const theme = useContext(ThemeContext);
return theme;
}

Para asegurarnos de que sea un tema válido, generemos un error si useContext(ThemeContext) devuelve un valor falso.

function useThemeContext() {
const theme = useContext(ThemeContext);
if (!theme) {
throw new Error("useThemeContext must be used within ThemeProvider");
}
return theme;
}

En lugar de envolver los componentes directamente con el ThemeContext.Provider componente, podemos crear un HOC que envuelva el componente para proporcionar sus valores. De esta manera, podemos separar la lógica del contexto de los componentes de renderizado, lo que mejora la reutilización del proveedor.

function ThemeProvider({ children }) {
const [theme, setTheme] = useState("dark");
function toggleTheme() {
setTheme(theme === "light" ? "dark" : "light");
}
const providerValue = {
theme: themes[theme],
toggleTheme,
};
return (
<ThemeContext.Provider value={providerValue}>
{children}
</ThemeContext.Provider>
);
}
export default function App() {
return (
<div className={`App theme-${theme}`}>
<ThemeProvider>
<Toggle />
<List />
</ThemeProvider>
</div>
);
}

Cada componente que necesita tener acceso a ThemeContext , ahora puede simplemente usar el useThemeContext gancho.

export default function TextBox() {
const theme = useThemeContext();
return <li style={theme.theme}>...</li>;
}

Al crear enlaces para los diferentes contextos, es fácil separar la lógica de los proveedores de los componentes que representan los datos.


Caso de estudio

Some libraries provide built-in providers, which values we can use in the consuming components. A good example of this, is styled-components.

No experience with styled-components is needed to understand this example.

The styled-components library provides a ThemeProvider for us. Each styled component will have access to the value of this provider! Instead of creating a context API ourselves, we can use the one that’s been provided to us!

Let’s use the same List example, and wrap the components in the ThemeProvider imported from the styled-component library.

import { ThemeProvider } from "styled-components";
export default function App() {
const [theme, setTheme] = useState("dark");
function toggleTheme() {
setTheme(theme === "light" ? "dark" : "light");
}
return (
<div className={`App theme-${theme}`}>
<ThemeProvider theme={themes[theme]}>
<Toggle toggleTheme={toggleTheme} />
<List />
</ThemeProvider>
</div>
);
}

En lugar de pasar un style accesorio en línea al ListItem componente, lo convertiremos en un styled.li componente. Como es un componente con estilo, podemos acceder al valor de theme !

import styled from "styled-components";
export default function ListItem() {
return (
<Li>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat.
</Li>
);
}
const Li = styled.li`
${({ theme }) => `
background-color: ${theme.backgroundColor};
color: ${theme.color};
`}
`;

¡Genial, ahora podemos aplicar estilos fácilmente a todos nuestros componentes con estilo con ThemeProvider !

Compensaciones

Ventajas

El patrón de proveedor/API de contexto hace posible pasar datos a muchos componentes, sin tener que pasarlos manualmente a través de cada capa de componente.

Reduce el riesgo de introducir errores accidentalmente al refactorizar el código. Anteriormente, si más adelante queríamos cambiar el nombre de un accesorio, teníamos que cambiar el nombre de este accesorio en toda la aplicación donde se usaba este valor.

Ya no tenemos que lidiar con la perforación de puntales , que podría verse como un antipatrón. Anteriormente, podía resultar difícil comprender el flujo de datos de la aplicación, ya que no siempre estaba claro dónde se originaban ciertos valores de propiedad. Con el patrón Proveedor, ya no tenemos que pasar accesorios innecesariamente a componentes que no se preocupan por estos datos.

Mantener algún tipo de estado global es fácil con el patrón Proveedor, ya que podemos dar acceso a los componentes a este estado global.

Contras

En algunos casos, el uso excesivo del patrón Proveedor puede provocar problemas de rendimiento. Todos los componentes que consumen el contexto se vuelven a representar en cada cambio de estado.

Veamos un ejemplo. Tenemos un contador simple cuyo valor aumenta cada vez que hacemos clic en el Increment botón del Button componente. También tenemos un Reset botón en el Reset componente, que restablece el conteo a 0 .

Sin embargo, cuando hace clic en Increment , puede ver que no es sólo el recuento lo que se vuelve a representar. ¡ La fecha en el Reset componente también se vuelve a representar!

El Reset componente también se volvió a renderizar ya que consumió el archivo useCountContext . En aplicaciones más pequeñas, esto no importará demasiado. En aplicaciones más grandes, pasar un valor actualizado con frecuencia a muchos componentes puede afectar negativamente el rendimiento.

Para asegurarse de que los componentes no consuman proveedores que contengan valores innecesarios que puedan actualizarse, puede crear varios proveedores para cada caso de uso por separado.

Relacionado

ForEach de Javascript: Array para bucles

Como una de las estructuras de control básicas en la programación, los bucles son casi una adición diaria al código que escribimos. El bucle forEach clásico es uno de los primeros fragmentos de código que aprendemos a escribir como programadores. Si fueras un desarrollador de Javascript, sabrías que Javascript no es ajeno a la iteración a través de los elementos de una matriz o un mapa ¡SEGUIR LEYENDO!

10 Mejores alternativas de Sci-hub para descargar artículos de investigación gratis

Como sabemos, Sci-hub es un sitio web increíble con millones de artículos de investigación para todos los estudiantes universitarios y académicos. El sitio web de Sci-Hub se encarga de obtener los artículos de investigación y artículos de pago utilizando las credenciales que se filtran. La fuente de credenciales utilizada por este sitio web no está clara. Sin embargo, se supone que muchas de ellas son donadas, ¡SEGUIR LEYENDO!

10 Características Sorprendentes de Windows que Deberías Conocer en 2024

Aunque haya sido usuario de Windows durante décadas, el sistema operativo es tan amplio y complejo que siempre existen características útiles, pero menos conocidas, que podrían sorprenderte. En este sentido, he identificado diez funciones poco conocidas de Windows que pueden potenciar su eficiencia, comodidad e incluso su experiencia de uso lúdico en su PC.

Microsoft Surface Go 2 - Portátil 2 en 1 de 10.5 pulgadas Full HD, Wifi, Intel...
  • Procesador Dual-Core Intel Pentium Gold 4425Y (2...
  • Memoria RAM de 8 GB LPDDR3
  • Disco SSD de 128 GB
Todas estas características deberían ser compatibles tanto con Windows 10 ¡SEGUIR LEYENDO!

10 Criptomonedas con Potencial de Crecimiento de Futuro

El rumor en torno a las criptomonedas no se desvanece por mucho que existan grandes pesimistas alrededor de los malos rumores. Entonces, si consideras invertir en el mundo de las criptomonedas, deberías estar atento a las criptomonedas que se espera que tengan un buen desempeño para el resto de 2021. En los últimos tiempos, los tokens DeFi están recibiendo toda la atención y es más que ¡SEGUIR LEYENDO!

10 Empresas de robótica más importantes del mundo

Los cambios de paradigma revolucionarios debido a los desarrollos de la robótica en todo el mundo están generando nuevos puntos de vista en muchos sectores, entre ellos en los de la industria y la tecnología. Con la ayuda de la Inteligencia Artificial, la tecnología produce resultados innovadores cada segundo y el campo de la robótica define y reconfigura su uso a cada instante. Cada día que ¡SEGUIR LEYENDO!

10 Frameworks que los Desarrolladores de Software deberían Aprender 2024

Bienvenidos desarrolladores web y de software, estamos en los inicios de 2023 y es posible que muchos se esten planteado sus objetivos para lo largo del año. Con anterioridad ya he compartidos las rutas de aprendizaje para un desarrollador front-end, un desarrollador full-stack o un desarrollador back-end entre otros muchos contenidos más. En este artículo, me gustaría compartir algunos de los mejores frameworks y bibliotecas para ¡SEGUIR LEYENDO!

10 Repositorio de GitHub que todo Desarrollador Web debería conocer

GitHub es el lugar que debes buscar cuando intentas mejorar como desarrollador, toda la información que necesitas está disponible en algún repositorio que alguien ya se ha molestado en indexar. Sin embargo, la parte complicado es encontrar el repositorio más adecuado. Es fácil sentirse perdido en todos los repositorios disponibles dentro de GitHub. Para ayudarte, he elaborado una lista de 10 repositorios de GitHub que pueden ¡SEGUIR LEYENDO!

10 Mejores billeteras sin custodia

Si se quiere lograr que DeFi tenga éxito, es crucial que las puertas de enlace para interactuar con la web 3 sean intuitivas, seguras y accesibles, manteniendo el espíritu central de ser el banco del futuro. En los últimos años, hemos visto mejoras drásticas en las carteras y otras herramientas de gestión de activos, lo que permite a los inversores y usuarios acceder de forma segura ¡SEGUIR LEYENDO!

21 Mejores Frameworks de Java

Si recién comienzas a programar con Java, puedes oje la guía para principiantes sobre Java que te guiará a través de todos los conceptos más importantes de Java que necesitas conocer, si pronto quieres comenzar a utilizar cualquier de los frameworks Java. Java es un lenguaje robusto y combinado con un framework Java, puede proporcionar las mejores soluciones para cualquier campo tecnológico, ya bien sea; un ¡SEGUIR LEYENDO!

11 Mejores Herramientas de Automatización de Pruebas para Interfaces de Usuario

¿Eres un profesional del testing y las pruebas de software? Si es así, ¿Qué herramienta de pruebas utilizas? Como la mayoría de las personas cuando comienzan en el control de calidad. es posible que tenga que dominar solo una o dos herramientas de prueba porque estás restringido a lo que estás utilizando en la empresa. Cualquiera que sea la razón, si usted es un profesional experimentado, ¡SEGUIR LEYENDO!

10 Mejores robots amigos que aparecen en películas (incluido Jeff de Finch)

Como demuestra la nueva película Finch de Apple+, los robots son excelentes amigos y hay bastantes memorables que aparecen en numerosas películas. 1. Baymax (Big Hero 6) Al igual que Pixar, Disney tiene la capacidad de crear personajes no humanos que sin embargo, tienen una gran cantidad de carisma y personalidad. Baymax, uno de los personajes principales de la película Big Hero 6 , es un ¡SEGUIR LEYENDO!