reactjsjavascriptfrontend

Higher-Order Components en React

Reutilizar código es una de las principales acciones que debemos realizar para mejorar la calidad de nuestro código, aprende a hacer en React con los Higher-Order Components

Uno de los aspectos en los cuales más nos obsesionamos los desarrolladores al momento de escribir código, es construir código que pueda ser reutilizable a lo largo de nuestro proyecto, lo cúal reduce la complejidad de nuestro proyecto y aumenta nuestra productividad como desarrolladores.

Y en este articulo voy a hablarte sobre Higher-Order Components (HOC), que no es más que una técnica usada en React, para poder reutilizar la lógica de un componente a lo largo de un proyecto y esto se logra concretamente con una función común y corriente que recibe como parámetro un componente y retorna un nuevo componente, cabe resaltar que esta técnica no hace parte del API de React, solo es un patrón utilizado para la reutilización de lógica.

Para poderlo ver más claramente miremos el siguiente ejemplo:

import React, { Component } from 'react';

class App extends Component {
 constructor(...props) {
     super(...props)
     this.state = { data: [] }
 }
 componentDidMount() {
    fetch('https://jsonplaceholder.typicode.com/posts')
    .then(response => response.json())
    .then(data => {
      this.setState({ data })
    })
    .catch(err => console.log(err.message))
 }
 
 render() {
    const { data } = this.state
     return (
           <ul>
               {data.map(post =>  <li key={post.id}>{post.title}</li> )}
           </ul>
     )
 }
}

export default App

En este componente App lo único que hacemos es realizar una petición usando fetch a una API que nos traera una lista de posts y con esos datos renderizamos una lista donde pondremos en cada item el título de ese post, hasta ahora muy bien, pero ¿cuantas veces no haces componentes asi en tu aplicación?, lo que se haria normalmente es volver a escribir el componentDidMount() en este componente, hacer el fetch actualizando un estado y renderizar estos datos, en estas tareas repetivivas es que nos servirán los HOC.

Para crear un HOC lo que debemos hacer es crear una función como la que muestro a continuación:

import React,{ Component } from 'react'

export default function withDataFetching(endpoint, WrappedComponent) {
  return class extends Component {
    constructor(props) {
      super(props)
      this.state = { data: [] }
    }

    componentDidMount() {
      fetch(endpoint)
        .then(response => response.json())
        .then(data => {
          this.setState({ data })
        })
        .catch(err => console.log(err.message))
    }

    render() {
      return <WrappedComponent data={this.state.data} {...this.props} />
    }
  }
}

Esta función que yo la llame withDataFetching() me recibe como parámetros, el endpoint al cual yo quiero hacer la petición, y el componente con el cual quiero trabajar, esta función me retorna un componente de React y dentro de este componente es que realizo la lógica que quiero reutilizar a lo largo de mi aplicación, en este caso hago la petición en el componentDidMount() al endpoint que recibo como parámetro actualizo el estado data y en el método render de este componente lo único que hago es retornar el componente que recibi como párametro inyectandole la nueva data y pasandole las propiedades.

Ya con esto hecho, en el componente App lo único que debemos hacer es ejecutar nuestra función withDataFetching() en el momento de exportar nuestro componente

export default withDataFetching('https://jsonplaceholder.typicode.com/posts', App)

Aqui solo pasamos el endpoint para nuestra consulta y nuestro componente App, esto lo que hara es que como párametro recibiremos la data consultada en el endpoint, y gracias a esto no necesitariamos hacer la petición en nuestro componente, con lo cual nuestro componente App quedaria algo asi:

import React,{ Component } from 'react';
import withDataFetching from './withDataFetching'

class App extends Component {
  render() {
    return (
      <ul>
        {this.props.data.map(post =>  <li key={post.id}>{post.title}</li> )}
      </ul>
    )
  }
}


export default withDataFetching('https://jsonplaceholder.typicode.com/posts', App)

Gracias a withDataFetching() podemos eliminar el estado local y el componentDidMount() ya que withDataFetching() se estara encargando de hacer la petición y mandarnos como párametro la data resultante, esto es muy beneficioso ya que nos permite reutilizar esta clase de lógica en cualquier componente de nuestra aplicación e incluso si nuestro componente App no requiere de más logica adicional podemos convertirlo en un componente presentacional, como lo puedes ver a continuación:

import React,{ Component } from 'react';
import withDataFetching from './withDataFetching'

const App = ({ data }) => (
  <ul>
    {data.map(post =>  <li key={post.id}>{post.title}</li> )}
  </ul>
)


export default withDataFetching('https://jsonplaceholder.typicode.com/posts', App)

Si quieres ver el codigo completo de este post te lo dejo en el siguiente link HOC

Hasta la próxima.