Limpieza de código JavaScript: cómo se puede refactorizar para usar clases

En proyectos React más pequeños, mantener todos los métodos de sus componentes en los propios componentes funciona bien. En proyectos de tamaño mediano, es posible que desee poder sacar esos métodos de sus componentes y convertirlos en un "ayudante". Aquí, le mostraré cómo usar una clase (en lugar de exportar funciones y variables individuales) para organizar su código.

Nota : Trabajo en React, así que ese es el ejemplo que discutiremos aquí.

Refactor típico

En una refactorización típica, tomaría una función en el componente y la movería a otro ayudante.

Desde:

const MyComponent = () => { const someFunction = () => 'Hey, I am text' return ( {someFunction()} ) }

A:

import { someFunction } from 'functionHelper.js' const MyComponent = () => { return ( {someFunction()} ) }

y

export const someFunction = () => 'Hey, I am text'

Este ejemplo es realmente tonto, pero ya ve a dónde vamos:

  1. Tome sus funciones y cópielas en un archivo separado
  2. Importarlos y llamarlos normalmente.

Sin embargo, cuando las cosas se complican, tendrá que pasar un montón de cosas a esas funciones: objetos, funciones para manipular el estado, etc. Hoy me encontré con un problema en el que quería extraer tres funciones de un componente y todas requerían las mismas entradas (una resourcey una función para actualizar la resource). Tiene que haber una forma mejor ...

Refactorizando con una clase

Hice una gran demostración para esta publicación. Puedes ver el código en Github. La confirmación inicial muestra toda la funcionalidad dentro del componente principal ( App.js) y las confirmaciones posteriores refactorizan el código para usar una clase.

Puede ejecutar esto usted mismo y hacer lo que quiera. Recuerda yarn install.

Comenzamos con un componente que "recupera" un objeto (imitando la forma en que podríamos hacer esto desde una API) con ciertos atributos: repetición (número de cajas), lado (alto y ancho), texto, color. Luego tenemos varias formas de manipular la vista: cambiar el color, actualizar el texto, etc. Después de cada cambio, mostramos un mensaje.

Por ejemplo, aquí está nuestro método de cambio de ancho y alto:

changeSide = side => { const obj = {...this.state.obj, side} this.fetchObject(obj); this.setState({ message: `You changed the sides to ${side} pixels!` }); }

Es posible que tengamos otros métodos que requieran acciones similares, o quizás métodos muy diferentes. Podríamos empezar a pensar en extraer este código a un ayudante. Luego, crearíamos un método diferente para llamar a la setStateacción y tendríamos que pasarlo this.fetchObject, el objeto en estado y el sideque estamos obteniendo como argumento del método. Si tenemos varios métodos similares, eso es una gran cantidad de parámetros de paso y tal vez no sea realmente tan útil (o legible).

En su lugar, podemos usar una clase, completa con un método constructor:

export default class ObjectManipulator { constructor( { object, fetchObject, markResettable, updateMessage, updateStateValue } ) { this.fetchObject = fetchObject; this.markResettable = markResettable; this.updateMessage = updateMessage; this.updateStateValue = updateStateValue; } changeSide = ( object, side ) => { const newObject = { ...object, side }; this.fetchObject(newObject); this.updateMessage(`You changed the sides to ${side} pixels!`); this.markResettable(); this.updateStateValue('side', side); }; };

Esto nos permite crear un objeto cuyas funciones podemos llamar dentro de nuestro componente principal:

const manipulator = new ObjectManipulator({ object, fetchObject: this.fetchObject, markResettable: this.markResettable, updateMessage: this.updateMessage, updateStateValue: this.updateStateValue, });

Esto crea un objeto manipulator, una instancia de nuestra ObjectManipulatorclase. Cuando lo llamemos manipulator.changeSide(object, '800'), se ejecutará el changeSidemétodo que definimos anteriormente. No es necesario pasar updateMessageni ninguno de los otros métodos; los recogemos del constructor cuando creamos la instancia.

Puede imaginar que esto se vuelve realmente útil si tenemos muchos de estos métodos con los que lidiar. En mi caso, necesitaba llamar a .then(res => myFunction(res) después de todo lo que estaba tratando de extraer. La definición ng myFunctde la instancia de la clase en lugar de pasarla a cada función me ahorró mucho código.

Manteniendo todo organizado

Este método de organización puede ser realmente útil para mantener todo en su lugar. Por ejemplo, tengo una variedad de colores que mapeo para obtener los botones de color que ves en el ejemplo. Al mover esta constante al ObjectManipulator, puedo asegurarme de que no choque con ninguna otra colorsen el resto de mi aplicación:

export default class ObjectManipulator { [...] colors = ['blue', 'red', 'orange', 'aquamarine', 'green', 'gray', 'magenta']; };

Puedo usar manipulator.colorspara tomar los colores correctos para esta página, mientras que puede haber una colorsconstante global que se usa para otra cosa.

Referencias

Buenos viejos documentos de Mozilla Class