Cómo encapsular un paquete de JavaScript para usarlo en React

Introducción
Los proyectos web complejos suelen requerir el uso de widgets de terceros. Pero ¿qué sucede si estás usando un framework y el widget solo está disponible en JavaScript puro?
Para utilizar un widget de JavaScript en su proyecto, el mejor enfoque sería crear un contenedor específico del marco.
ag-Grid
es un widget de JavaScript para mostrar información en una cuadrícula de datos. Le permite ordenar, filtrar y seleccionar información de forma dinámica. ag-Grid
También proporciona un contenedor de React, ag-grid-react
.
En este artículo, utilizarás ag-grid-community
y ag-grid-react
como base para aprender a encapsular un widget de terceros en un componente de React. Configurarás la asignación entre React Props y las opciones de configuración del widget. Además, expondrás la API de un widget a través de un componente de React.
Prerrequisitos
Para seguir este artículo necesitarás:
- Si tienes alguna familiaridad con React, puedes echar un vistazo a nuestra serie Cómo programar en React.js .
Paso 1: Comprender el widget de JavaScript
En general, la mayoría de los widgets de JavaScript tienen:
- Opciones de configuración
- Una API pública
- Eventos retransmitidos
Así es exactamente como interactúas con ag-Grid
. Puedes encontrar una buena descripción de las propiedades, eventos, devoluciones de llamadas y API de la cuadrícula en la documentación oficial .
En resumen, la cuadrícula de datos define:
- Propiedades de cuadrícula que habilitan funciones de la cuadrícula, como la animación de filas.
- API de cuadrícula para interactuar con la cuadrícula en tiempo de ejecución (por ejemplo, para obtener todas las filas seleccionadas)
- Eventos de cuadrícula emitidos por la cuadrícula cuando ocurren ciertos eventos en la cuadrícula, como la clasificación de filas o la selección de filas
- Las devoluciones de llamada de la cuadrícula se utilizan para proporcionar información desde su aplicación a la cuadrícula cuando la necesita (por ejemplo, se llama a una devolución de llamada cada vez que se muestra un menú que permite que su aplicación personalice el menú)
A continuación se muestra una configuración básica de JavaScript puro que demuestra el uso de las opciones de cuadrícula:
let gridOptions = { // PROPERTIES - object properties, myRowData and myColDefs are created somewhere in your application rowData: myRowData, columnDefs: myColDefs, // PROPERTIES - simple boolean / string / number properties pagination: true, rowSelection: 'single', // EVENTS - add event callback handlers onRowClicked: function(event) { console.log('a row was clicked'); }, onColumnResized: function(event) { console.log('a column was resized'); }, onGridReady: function(event) { console.log('the grid is now ready'); }, // CALLBACKS isScrollLag: function() { return false; }}
Primero, la cuadrícula de datos de JavaScript se inicializa de la siguiente manera:
new Grid(this._nativeElement, this.gridOptions, ...);
Luego, ag-Grid
adjunta el objeto con métodos API que gridOptions
se pueden usar para controlar la cuadrícula de datos de JavaScript:
// get the grid to refreshgridOptions.api.refreshView();
Sin embargo, cuando ag-Grid
se utiliza como un componente de React, no creamos una instancia de la cuadrícula de datos directamente. Esa es la tarea del componente contenedor. Todas las interacciones con la instancia de ag-Grid
ocurren a través de la instancia del componente.
Por ejemplo, no tenemos acceso directo al objeto API asociado a la cuadrícula. Accederemos a él a través de la instancia del componente.
Paso 2: determinar qué debe hacer un componente contenedor
Nunca pasamos opciones de configuración ni devoluciones de llamadas directamente a la red. Un componente contenedor de React toma las opciones y las devoluciones de llamadas a través de React Props.
Todas las opciones de cuadrícula que están disponibles para la cuadrícula de JavaScript estándar también deberían estar disponibles en la cuadrícula de datos de Reactag-Grid
. Tampoco escuchamos directamente los eventos en la instancia de . Si lo usamos ag-Grid
como un componente de React, todos los eventos emitidos por ag-Grid
deberían estar disponibles a través de las propiedades de los componentes de React.
Todo esto significa que un contenedor de cuadrícula de datos específico de React ag-Grid
debería:
- Implementar un mapeo entre enlaces de entrada (como
rowData
) yag-Grid
las opciones de configuración de - Debe escuchar los eventos emitidos por
ag-Grid
y definirlos como salidas de componentes. - escuchar los cambios en los enlaces de entrada del componente y actualizar las opciones de configuración en la cuadrícula
- Exponer API adjunta a
ag-Grid
travésgridOptions
de sus propiedades
El siguiente ejemplo demuestra cómo se configura la cuadrícula de datos de React en una plantilla utilizando React Props:
AgGridReact // useful for accessing the component directly via ref - optional ref="agGrid" // simple attributes, not bound to any state or prop rowSelection="multiple" // these are bound props, so can use anything in React state or props columnDefs={this.props.columnDefs} showToolPanel={this.state.showToolPanel} // this is a callback isScrollLag={this.myIsScrollLagFunction} // these are registering event callbacks onCellClicked={this.onCellClicked} onColumnResized={this.onColumnEvent} // inside onGridReady, you receive the grid APIs if you want them onGridReady={this.onGridReady}/
Ahora que entendemos el requisito, veamos cómo lo implementamos en ag-Grid
.
Paso 3: Implementación de un contenedor de React
Primero, necesitamos definir un componente React AgGridReact
que represente nuestra cuadrícula de datos React en plantillas. Este componente renderizará un DIV
elemento que servirá como contenedor para la cuadrícula de datos. Para obtener el DIV
elemento nativo, usamos la funcionalidad Refs :
export class AgGridReact extends React.Component { protected eGridDiv: HTMLElement; render() { return React.createElement("div", { style: ..., ref: e = { this.eGridDiv = e; } }, ...); }}
Antes de poder crear una instancia ag-Grid
, también debemos recopilar todas las opciones. Todas ag-Grid
las propiedades y eventos vienen como React Props en el AgGridReact
componente. La gridOptions
propiedad se usa para almacenar todas las opciones de la cuadrícula de datos. Necesitamos copiar todas las opciones de configuración de React Props tan pronto como estén disponibles.
Para ello, hemos implementado la copyAttributesToGridOptions
función. Se trata de una función de utilidad que copia propiedades de un objeto a otro:
export class ComponentUtil { ... public static copyAttributesToGridOptions(gridOptions, component, ...) { ... // copy all grid properties to gridOptions object ComponentUtil.ARRAY_PROPERTIES .concat(ComponentUtil.STRING_PROPERTIES) .concat(ComponentUtil.OBJECT_PROPERTIES) .concat(ComponentUtil.FUNCTION_PROPERTIES) .forEach(key = { if (typeof component[key] !== 'undefined') { gridOptions[key] = component[key]; } }); ... return gridOptions; }}
Las opciones se copian en el componentDidMount
método de ciclo de vida después de que se hayan actualizado todas las propiedades. Este es también el gancho donde instanciamos la cuadrícula. Necesitamos pasar un elemento DOM nativo a la cuadrícula de datos cuando se instancia, por lo que usaremos el DIV
elemento capturado mediante la funcionalidad de referencias:
export class AgGridReact extends React.Component { gridOptions: AgGrid.GridOptions; componentDidMount() { ... let gridOptions = this.props.gridOptions || {}; if (AgGridColumn.hasChildColumns(this.props)) { gridOptions.columnDefs = AgGridColumn.mapChildColumnDefs(this.props); } this.gridOptions = AgGrid.ComponentUtil.copyAttributesToGridOptions(gridOptions, this.props); new AgGrid.Grid(this.eGridDiv, this.gridOptions, gridParams); this.api = this.gridOptions.api; this.columnApi = this.gridOptions.columnApi; }}
Arriba puedes ver que también verificamos si hay elementos secundarios que se pasan como columnas y los agregamos a las opciones de configuración como definiciones de columnas:
if (AgGridColumn.hasChildColumns(this.props)) { gridOptions.columnDefs = AgGridColumn.mapChildColumnDefs(this.props);}
Paso 4: Sincronización de las actualizaciones de las propiedades de la cuadrícula
Una vez que se inicializa la cuadrícula, debemos realizar un seguimiento de los cambios en React Props para actualizar las opciones de configuración de la cuadrícula de datos. ag-Grid
Implementa una API para hacer eso. Por ejemplo, si la headerHeight
propiedad cambia, existe un setHeaderHeight
método para actualizar la altura de un encabezado.
React utiliza componentWillReceiveProps
el método de ciclo de vida para notificar a un componente sobre los cambios. Aquí es donde colocamos nuestra lógica de actualización:
export class AgGridReact extends React.Component { componentWillReceiveProps(nextProps: any) { const changes = any{}; const changedKeys = Object.keys(nextProps); changedKeys.forEach((propKey) = { ... if (!this.areEquivalent(this.props[propKey], nextProps[propKey])) { changes[propKey] = { previousValue: this.props[propKey], currentValue: nextProps[propKey] }; } }); AgGrid.ComponentUtil.getEventCallbacks().forEach((funcName: string) = { if (this.props[funcName] !== nextProps[funcName]) { changes[funcName] = { previousValue: this.props[funcName], currentValue: nextProps[funcName] }; } }); AgGrid.ComponentUtil.processOnChange(changes, this.gridOptions, this.api, this.columnApi); }}
Básicamente, revisamos la lista de ag-Grid
propiedades de configuración y devoluciones de llamadas y verificamos si alguna de ellas ha cambiado. Colocamos todos los cambios en la changes
matriz y luego los procesamos usando processOnChange
el método.
El método hace dos cosas. Primero, revisa los cambios en React Props y actualiza las propiedades del gridOptions
objeto. Luego, llama a los métodos de API para notificar a la cuadrícula sobre los cambios:
export class ComponentUtil { public static processOnChange(changes, gridOptions, api, ...) { ... // reflect the changes in the gridOptions object ComponentUtil.ARRAY_PROPERTIES .concat(ComponentUtil.OBJECT_PROPERTIES) .concat(ComponentUtil.STRING_PROPERTIES) .forEach(key = { if (changes[key]) { gridOptions[key] = changes[key].currentValue; } }); ... // notify Grid about the changes in header height if (changes.headerHeight) { api.setHeaderHeight(changes.headerHeight.currentValue); } // notify Grid about the changes in page size if (changes.paginationPageSize) { api.paginationSetPageSize(changes.paginationPageSize.currentValue); } ... }}
Paso 5: Exponer la API
La interacción con la cuadrícula de React en tiempo de ejecución se realiza a través de la API de cuadrícula. Es posible que desee ajustar el tamaño de las columnas, establecer nuevas fuentes de datos, obtener una lista de todas las filas seleccionadas, etc. Cuando se inicia la cuadrícula de datos de JavaScript, adjunta el api
objeto al objeto de opciones de cuadrícula. Para exponer este objeto, lo asignamos a la instancia del componente:
export class AgGridReact extends React.Component { componentDidMount() { ... new AgGrid.Grid(this.eGridDiv, this.gridOptions, gridParams); this.api = this.gridOptions.api; this.columnApi = this.gridOptions.columnApi; }}
Y eso es todo.
Conclusión
En este tutorial, aprendimos cómo adaptar una biblioteca de JavaScript básica para que funcione dentro del marco React.
Para obtener más información sobre este tema, puede consultar la documentación oficial de React en “Integración con otras bibliotecas” .
Deja una respuesta