Hook para manejar la API de Context useContext

El hook useContext nos sirve para poder implementar la API de Context que ya existía en React desde antes de los hooks.

const value = useContext(MyContext);

Para quien no esté familiarizado, Context nos permite comunicar props en un árbol de componentes sin necesidad de pasarlos manualmente a través de props.

Algunos ejemplos de cuándo utilizar Context son:

  • Un Tema de la UI (light theme, dark theme, etc).
  • Autenticación del usuario.
  • Idioma preferido.

Pero no es limitado a los ejemplos anteriores. Puedes aplicar Context a las necesidades de tu aplicación según tu criterio.

En otras palabras, no es obligatorio que Context maneje un “estado global” de la aplicación: Puede abarcar sólo una parte del estado si lo deseas.

A continuación vamos a ver ejemplos y comparaciones de cómo utilizar este hook para que puedas aprovechar todo su potencial.

Hook useContext VS clase

Primero implementaremos un Context para aplicar un tema en componentes usando la API tradicional y luego lo refactorizaremos usando useContext.

Esto es sólo para poder identificar las semejanzas y diferencias entre ambas opciones. No quiere decir que la manera tradicional sea obsoleta ni nada por el estilo.

Dicho lo anterior, comenzaremos creando un Context para manejar el tema del siguiente modo:

 1 // theme-context.js
2
3 export const themes = {
4 light: {
5 color: "#555555",
6 background: "#eeeeee"
7 },
8 dark: {
9 color: "#eeeeee",
10 background: "#222222"
11 },
12 vaporwave: {
13 color: "#ffffff",
14 background: "#ff71ce"
15 }
16 };
17
18 export const ThemeContext = React.createContext(themes.light);

En este caso tenemos un objeto para representar temas diferentes que podemos usar en nuestra UI.

El tema por defecto es themes.light que es pasado por parámetro a createContext.

Ahora necesitamos proveer este context a nuestro árbol de componentes:

 1 export default function App() {
2 const [currentTheme, setCurrentTheme] =
3 useState(themes.light);
4
5 return (
6 <div className="App">
7 <h1>React Context</h1>
8
9 <ThemeContext.Provider value={currentTheme}>
10 <MyButton>Hello World!</MyButton>
11 </ThemeContext.Provider>
12 </div>
13 );
14 }

Estamos creando una variable de estado con useState para obtener el valor actual del tema.

Usamos ThemeContext.Provider value={currentTheme}para asignar el context y a partir de aquí, todo el árbol de componentes hijos van a poder tener acceso a context si lo desean.

Para usarlo en un componente lo hacemos del siguiente modo:

 1 class MyButton extends Component {
2 render() {
3 const theme = this.context;
4 const style = {
5 backgroundColor: theme.background,
6 color: theme.color,
7 border: "1px solid",
8 borderRadius: 5
9 };
10 return <button style={style} {...this.props} />;
11 }
12 }
13
14 // Esto es importante (asignar el context)
15 MyButton.contextType = ThemeContext;

Y con esto ya tenemos nuestro context funcionando.

Ahora si queremos modificar el context, en este ejemplo basta con hacer lo que sigue:

 1 export default function App() {
2 const [currentTheme, setCurrentTheme] = useState(themes.light);
3
4 return (
5 <div className="App">
6 <h1>React Context</h1>
7 <ThemeContext.Provider value={currentTheme}>
8 <MyButton
9 onClick={() => setCurrentTheme(themes.dark)}
10 >
11 Dark Theme
12 </MyButton>
13 <MyButton
14 onClick={() => setCurrentTheme(themes.vaporwave)}
15 >
16 Vaporwave Theme
17 </MyButton>
18 </ThemeContext.Provider>
19 </div>
20 );
21 }

Con esto ya funciona pero por lo común vas a tener la necesidad de modificar el context desde un componente hijo.

Para eso podemos modificar nuestro context para proveer su valor y además una función que sirva para modificar su valor.

Primero modificamos nuestro context:

1 export const ThemeContext = React.createContext({
2 theme: themes.light,
3 updateTheme: () => {}
4 });

Ahora tendrá un objeto con las dos propiedades antes dichas.

En donde hacemos uso de Provider necesitamos modificar también su valor:

 1 export default function App() {
2 const [currentTheme, setCurrentTheme] = useState(themes.light);
3
4 return (
5 <div className="App">
6 <h1>React Context</h1>
7
8 {/* Nuevo value definido */}
9 <ThemeContext.Provider
10 value={{
11 theme: currentTheme,
12 updateTheme: setCurrentTheme
13 }}
14 >
15 <MyButton
16 onClick={() => setCurrentTheme(themes.dark)}
17 >
18 Dark Theme
19 </MyButton>
20
21 <MyButton
22 onClick={() => setCurrentTheme(themes.vaporwave)}
23 >
24 Vaporwave Theme
25 </MyButton>
26
27 {/* Nuevo Boton sin onClick */}
28 <MyButton>Light Theme</MyButton>
29 </ThemeContext.Provider>
30 </div>
31 );
32 }

En el componente MyButton vamos a hacer que si no recibe el prop de onClick, pondremos por default updateThemeque obtenemos de ThemeContext:

 1 class MyButton extends Component {
2 render() {
3 const { theme, updateTheme } = this.context;
4 const style = {
5 backgroundColor: theme.background,
6 color: theme.color,
7 border: "1px solid",
8 borderRadius: 5
9 };
10
11 const updateLightTheme = () => {
12 updateTheme(themes.light);
13 };
14
15 const onClick = this.props.handleClick ||
16 updateLightTheme;
17
18 return <button
19 onClick={onClick}
20 style={style}
21 {...this.props}
22 />;
23 }
24 }

Con esto ya estamos actualizando context desde un componente hijo o de manera directa en el componente donde hacemos el provider.

Ahora vamos a hacer una nueva versión del código anterior para hacer uso de useContext y puedas apreciar las diferencias.

La definición de ThemeContext no necesitamos modificarla, ni el Provider.

Lo que nos va a servir useContext es para poder acceder al valor de un context en un componente funcional.

 1 const MyNewButton = (props) => {
2 const { theme, updateTheme } = useContext(ThemeContext);
3
4 const style = {
5 backgroundColor: theme.background,
6 color: theme.color,
7 border: "1px solid",
8 borderRadius: 5
9 };
10
11 const updateLightTheme = () => {
12 updateTheme(themes.light);
13 };
14
15 const onClick = props.handleClick || updateLightTheme;
16
17 return <button onClick={onClick} {...props} style={style} />;
18 };

Como puedes ver, lo único que cambia es que ahora podemos obtener nuestro valor de context usando const { theme, updateTheme } = useContext(ThemeContext);.

Con esto cubrimos el tema de Context en sí mismo y el hook useContext.

Prueba y edita el código fuente aquí:

Descarga el Ebook React Hooks Manual desde cero gratis

Este post es un extracto del ebook publicado en Amazon: React Hooks Manual Desde Cero. Lo puedes descargar GRATIS a través de mi sitio web 🤓.

Recapitulación del hook useContext

En este capítulo hemos visto:

  • Cómo es el uso básico api de Context.
  • Algunos casos de uso en los cuáles puedes aplicar Context.
  • Una manera de aplicar Context en componente de tipo clase.
  • La manera de aplicar Context con el hook useContext.

Espero que este capítulo te haya sido de utilidad.

¿Te ha gustado el contenido?

Te invito a darle clap (1, 10, 50, los que quieras!)👏 y compartirlo! Puedes subscribirte a mi canal de YouTube y al blog de Developero para más contenidos de este tipo ⚡️🤘.

--

--

Full Stack JS Engineer — Developero founder — Software Development Ebooks author. https://developero.io

Love podcasts or audiobooks? Learn on the go with our new app.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Juan Correa

Juan Correa

Full Stack JS Engineer — Developero founder — Software Development Ebooks author. https://developero.io