Cover - React Provider pattern

React Provider – Patron de diseño

Los patrones de diseño son una super herramientas a la hora de desarrollar alguna funcionalidad en nuestras aplicaciones si son usados con sabiduría al igual que pueden ser un gran problema si lo implementamos simplemente por usarlo y no por necesitarlo, en este tutorial estaremos implementando el patron Provider junto a React.

Recientemente mientras trabajaba con react-redux, me hice la pregunta cómo funcionaba la función connect que me permite acceder al store de la aplicación mediante dicha función, y quise ver como funcionaba, al final me gusto mucho y lo encontré bastante útil así que me decidí a escribir para que demás personas pueda ver la magia detrás de esto.

Este patrón diseño Provider es muy útil para trabajar con React

Problema

Imaginemos que tenemos un componente padre que maneja ciertas propiedades, y queremos que un componente hijo de hijo tenga acceso a esa propiedad, para lograr algo como esto tendríamos que hacer algo como esto:

const App = () => (
   <div style={styles}>
       <Padre propiedad="Hola Mundo!" />
   </div>

);

const Hijo = (props) => {
  return (
    <div>
      <b>{ props.propiedad }</b>
    </div>

  );
};

const Padre = (props) => {
  return (
    <div>
      <Hijo propiedad={props.propiedad} />
    </div>

  );
}

Como podrán notar esto es inmantenible a la hora de crear una aplicación grande, tendríamos que estar pasando esta ‘propiedad’ componente por componente y es muy propenso a errores (Si tenemos nuestras unit test se puede detectar fácil pero eso es otra historia.).

Solución

En la solución es donde entrar nuestro patrón de diseño Provider donde hacemos uso tanto de los conceptos Hight Order Component y del Context API de React.

Nuestra solución tendrá una estructura como la mostrada en la imagen anterior.

Los primeros pasos que tenemos que hacer es crear nuestro componente Proveedor el cual sera quien definirá las informaciones que pasaremos a todos los componentes que lo soliciten:

class ComponenteProvider extends React.Component {
  getChildContext() {
    return {
      titulo: this.props.titulo,
      detalles: this.props.detalles
    }
  }

  render(){
    return (
      <div>
        {this.props.children}
      </div>
    );
  }
}

ComponenteProvider.childContextTypes = {
  titulo: PropTypes.string,
  detalles: PropTypes.string,
};

Luego de la versión v15.5 de React hay que instalar el paquete npm install prop-types para poder utilizar PropsTypes.

En el bloque de código anterior simplemente declaramos un componente y el contexto que estará manejando para luego ser solicitado por sus componentes hijos, pueden ser hijos de hijos, todos en la jerarquía tienen acceso a dicho contexto.

Ahora vamos a crear nuestro conector que sera quien haga la conexión entre el proveedor y el componente el cual va a querer consumir el contexto ofrecido por el proveedor:

const connectar = (Componente) => {
  class ComponenteConectado extends React.Component{
    render(){
      return <Componente {...this.props} {...this.context} />;
    }
  }

  ComponenteConectado.contextTypes = {
    titulo: PropTypes.string,
    detalles: PropTypes.string,
  };

  return ComponenteConectado;
}

En el código anterior simplemente creamos una función la cual esta creando un componente que servirá como envoltura para nuestro componente original y este a su vez estará pasando el contexto como propiedades del componente, tener en cuenta que aquí utilizamos el contextTypes el cual tiene que ser la misma estructura de contexto que nuestro Componente Provider ya que aquí estaremos definiendo la estructura que estaremos consumido y tendremos disponibles en nuestros Componentes Conectados.

Una vez realizado esto ya tenemos completado nuestro patrón Provider, solo tenemos que utilizarlo con algún componente:

const Hijo = (props) => {
  return (
    <div>
        <h3>{props.titulo}</h3>
        <p>{props.detalles}</p>
    </div>
  );
};

const ComponenteHijoContectado = connectar(Hijo);

const Padre = (props) => {
  return (
    <div>
      <ComponenteHijoContectado />
    </div>
  );
}

const contenido = <ComponenteProvider 
    titulo="Titulo pagina" 
    detalles="detalles pagina">
  <Padre />
</ComponenteProvider>;

Como pueden notar en nuestro componente hijo estamos accediendo a las propiedades titulo y detalles y en ningún lado le estamos pasando esas propiedades directamente sino que cuando conectamos nuestro componente Hijo el contexto del Provider lo estamos convirtiendo en propiedades y así este componente tendrá acceso a todo lo del provider.

Ejemplo Completo

 

Referencias

Prop Types
Hight order Components
React Context