Gestión de estados en Gatsby mediante el gancho wrapRootElement

Dado que Gatsby se encarga de nuestras rutas, no nos queda ningún lugar donde encapsular nuestra aplicación con una tienda o proveedor de Redux. En este artículo, aprenderemos un truco inteligente para solucionar este problema.
Para simplificar, todos los ejemplos utilizarán la API de contexto de React para la gestión de estados y ahorrarán tiempo en la configuración de código repetitivo, pero todo sigue siendo aplicable a otros métodos de gestión de estados. Si necesitas repasar cómo trabajar con proveedores, puedes consultar esta introducción al gancho useContext.
Instalación
Prefiero empezar con un tema muy básico, pero al final solo necesitamos algo con dos páginas para que podamos ver que nuestro estado se está aplicando globalmente. Como trabajaremos con algunos estilos, agregaré soporte para Sass con node-sass
y gatsby-plugin-sass
, porque no soy un animal.
$ gatsby new stateful-gatsby https://github.com/gatsbyjs/gatsby-starter-defaultCopyInstall$ cd stateful-gatsby$ yarn add node-sass gatsby-plugin-sass -D
Envolviendo con Proveedor
El primer paso es configurar nuestro proveedor de contexto con un isDark
estado simple y un método para revertir su estado actual. Tomaremos lo que se pase como propiedades y lo incluiremos en nuestro nuevo myContext.Provider
.
proveedor.js
import React, { useState } from 'react';export const myContext = React.createContext();const Provider = props = { const [isDark, setTheme] = useState(false); return ( myContext.Provider value={{ isDark, changeTheme: () = setTheme(!isDark) }} {props.children} /myContext.Provider )};
Justo debajo, exportaremos una función que envolverá todo lo que se le pase en nuestro nuevo proveedor.
export default ({ element }) = ( Provider {element} /Provider);
Ahora que tenemos una forma de administrar nuestro estado, Gatsby nos ofrece un pequeño y elegante gancho llamado wrapRootElement
, que puedes consultar en la documentación. Este gancho toma la mayor parte de nuestro sitio y lo pasa como propiedades a una función que le damos, como la que acabamos de exportar desde Provider.js
, lo que nos da el pequeño espacio perfecto para incluir todo dentro.
Tanto gatsby-browser.js
y gatsby-ssr.js
tienen acceso a este gancho y se recomienda envolver ambos con nuestro proveedor, por eso definimos la función envolvente en provider.js
.
import Provider from './provider';export const wrapRootElement = Provider;
Estilo
Aquí están nuestros estilos de temas simples:
origen/global.sass
.colorTheme height: 100vh transition: .3s ease-in-out.darkTheme @extend .colorTheme background-color: #1A202C color: #fff a color: yellow.lightTheme @extend .colorTheme background-color: #fff color: #000
Aplicación de temas
Lo único que debemos hacer para acceder a nuestro estado es envolver cada componente en un myContext.Consumer
y acceder a nuestro estado global en context
React.Fragment es solo para permitirnos agregar más de un elemento.
Para nuestro color de fondo podemos establecer nuestra clase condicionalmente a nuestro estado, si tuviera más de un tema podría establecer el tema del proveedor como una cadena con nuestro nombre de clase.
diseño.js
import { myContext } from '../../provider';import '../global.sass'; return ( myContext.Consumer {context = ( React.Fragment div className={context.isDark ? 'darkTheme' : 'lightTheme'} {/* ... */} /div /React.Fragment )} /myContext.Consumer )
También tenemos acceso a setTheme
porque se lo pasamos al changeTheme
método. Agreguemos un botón a reverse isDark
.
src/paginas/index.js
import { myContext } from '../../provider';const IndexPage = () = ( Layout myContext.Consumer {context = ( React.Fragment SEO / h1{context.isDark ? "Dark Theme" : "Light Theme"}/h1 button onClick={() = context.changeTheme()}{context.isDark ? "Light" : "Dark"}/button Link to="/page-2/"Go to page 2/Link /React.Fragment )} /myContext.Consumer /Layout);
Ahora bien, si agrega esencialmente la misma configuración, page-2.js
debería poder cambiar el estado y moverse entre ellos sin que el estado se desvanezca entre ellos.
página-2.js
import { myContext } from '../../provider';const SecondPage = () = ( Layout myContext.Consumer {context = ( React.Fragment SEO / h1{context.isDark ? "Dark Theme" : "Light Theme"}/h1 pWelcome to page 2/p button onClick={() = context.changeTheme()}{context.isDark ? "Light" : "Dark"}/button Link to="/"Go back to the homepage/Link /React.Fragment )} /myContext.Consumer /Layout);
¡Hurra! Es así de simple: 3 pequeños cambios de archivo y empaquetar todo en un consumidor y listo.
Conclusión
Para mí, esta no era una forma muy obvia de hacer las cosas, así que espero que esto haya sido útil para comprender cómo usar el wrapRootElement
gancho a su favor.
Para mayor comodidad, he creado un repositorio con esta configuración como inicio, que puedes consultar aquí.
Deja una respuesta