Trabajar con datos en React es relativamente fácil porque React está diseñado para manejar datos como estado. La molestia comienza cuando la cantidad de datos que necesita consumir se vuelve masiva. Por ejemplo, digamos que tiene que manejar un conjunto de datos que tiene entre 500 y 1000 registros. Esto puede provocar cargas masivas y problemas de rendimiento de los cables. Bueno, veremos cómo podemos hacer uso de listas virtualizadas en React para representar sin problemas una larga lista de datos en su aplicación.
Usaremos el componente React Virtualized para obtener lo que necesitamos. Nos permitirá tomar grandes conjuntos de datos, procesarlos sobre la marcha y renderizarlos con poco o ningún jank.
La puesta en marcha
React Virtualized ya tiene un conjunto detallado de instrucciones para ponerlo en funcionamiento, así que consulte el repositorio para comenzar.
Vamos a querer que los datos trabajen, así que configuraremos una función que use faker para crear un gran conjunto de datos.
function createRecord(count) {
let records = [];
for (let i = 0; i < count; i++) {
records.push({
username: faker.internet.userName(),
email: faker.internet.email()
});
}
return records;
}
A continuación, le pasaremos la cantidad de registros de datos que queremos crear, así:
const records = createRecord(1000);
Muy bien, ahora tenemos lo que necesitamos para trabajar en la renderización de una lista de esos registros.
Creando una lista virtualizada
Aquí está la lista que queremos crear, sin estilo. Podríamos hacer uso de los pocos estilos de presentación que incluye la biblioteca importando el archivo CSS incluido, pero lo dejaremos fuera en esta publicación.
Vea Pen React Virtualized 1 de Kingsley Silas Chijioke (@kinsomicrote) en CodePen.
Continúe y vuelva a ejecutar esa demostración. Loco rápido, ¿verdad?
Quizás se pregunte qué diablos está haciendo React Virtualized detrás de escena para que eso suceda. Resulta que es un montón de tamaños, posicionamientos, transformaciones y transiciones locos y geniales que permiten que los registros se desplacen dentro y fuera de la vista. Los datos ya están allí y procesados. React Virtualized crea un marco de ventana que permite que los registros entren y salgan de la vista a medida que el usuario se desplaza por ellos.
Para renderizar una lista virtualizada en React Virtualized, hacemos uso de su List
componente, que utiliza un Grid
componente internamente para representar la lista.
Primero, comenzamos configurando rowRenderer
, que se encarga de mostrar una sola fila y establece un índice que asigna un ID a cada registro.
rowRenderer = ({ index, isScrolling, key, style }) => {
return (
<div key={key} style={style}>
<div>{this.props.data[index].username}</div>
<div>{this.props.data[index].email}</div>
</div>
);
};
Como puede ver, esto devuelve un solo nodo div que contiene dos divs adicionales: uno para el nombre de usuario y otro para el correo electrónico. Ya sabes, un patrón de lista común para mostrar usuarios.
rowRenderer
acepta varios parámetros. Esto es lo que son y lo que hace cada uno:
index
: El ID numérico de un registro.isScrolling
: Indica si el desplazamiento se está produciendo en elList
componente.isVisible
: Determina si una fila está visible o no.key
: La posición de los registros en la matriz.parent
: Define si la lista es padre o hijo de otra lista.style
: Un objeto de estilo para colocar la fila.
Ahora que sabemos más sobre el rowRenderer
función, vamos a ponerlo en uso en la List
componente:
<List
rowCount={this.props.data.length}
width={width}
height={height}
rowHeight={rowHeight}
rowRenderer={this.rowRenderer}
overscanRowCount={3}
/>
Es posible que haya notado algunos parámetros nuevos. Esto es lo que son:
rowCount
: Esto toma los números de una fila en una lista que pasamos para calcular la longitud de nuestra lista.width
: El ancho de la lista.height
: La altura de la lista.rowHeight
: Puede ser un número o una función que devuelve una altura de fila dado su índice.rowRenderer
: Esto es responsable de renderizar la fila. no se supone que la lista se pase directamente, por lo que pasamos elrowRenderer
función que creamos en este tutorial.overscanRowCount
: Se utiliza para representar filas adicionales en la dirección en la que el usuario se desplaza. Reduce las posibilidades de que el usuario se desplace más rápido de lo que se representa el contenido virtualizado.
Al final, su código debería verse así;
const { List } = ReactVirtualized
...
const height = 700;
const rowHeight = 40;
const width = 800;
class App extends React.Component {
rowRenderer = ({ index, isScrolling, key, style }) => {
return (
<div key={key} style={style}>
<div>{this.props.data[index].username}</div>
<div>{this.props.data[index].email}</div>
</div>
);
};
render() {
return (
<div>
<h2>Details</h2>
<List
rowCount={this.props.data.length}
width={width}
height={height}
rowHeight={rowHeight}
rowRenderer={this.rowRenderer}
overscanRowCount={3}
/>
</div>
);
}
}
Medidor de células
Según la documentación, un medidor de celda es un componente de orden superior que se utiliza para representar temporalmente una lista. Aún no es visible para el usuario en este momento, pero los datos están retenidos y listos para mostrarse.
¿Por qué debería preocuparte por esto? El caso de uso popular es una situación en la que el valor de su rowHeight
es dinámico. React Virtualized puede representar la altura de la fila en el procesamiento y luego almacenar en caché esa altura para que ya no necesite calcular a medida que los datos se desplazan fuera de la vista: ¡siempre es la altura correcta, sin importar el contenido que contenga!
Primero, creamos nuestro cache
, que se puede hacer en el constructor de nuestro componente usando CellMeasurerCache
:
constructor() {
super()
this.cache = new CellMeasurerCache({
fixedWidth: true,
defaultHeight: 100
})
}
Hacemos uso de la caché cuando configuramos el List
componente;
<List
rowCount={this.props.data.length}
width={rowWidth}
height={listHeight}
deferredMeasurementCache={this.cache}
rowHeight={this.cache.rowHeight}
rowRenderer={this.renderRow}
overscanRowCount={3}
/>
El valor pasado a deferredMeasurementCache
se utilizará para representar temporalmente los datos, luego, como el valor calculado para rowHeight
entra – filas adicionales fluirán como si siempre hubieran estado allí.
A continuación, sin embargo, haremos uso de React Virtualized CellMeasurer
componente dentro de nuestro rowRenderer
función en lugar del div que configuramos inicialmente como marcador de posición:
rowRenderer = ({ index, parent, key, style }) => {
return (
<CellMeasurer
key={key}
cache={this.cache}
parent={parent}
columnIndex={0}
rowIndex={index}
>
<div style={style}>
<div>{this.props.data[index].username}</div>
<div>{this.props.data[index].email}</div>
</div>
</CellMeasurer>
);
};
¡Ahora los datos se obtienen, se almacenan en caché y están listos para mostrarse en la ventana virtual a voluntad!
Mesa virtualizada
Sí, el punto principal de esta publicación es cubrir listas, pero ¿qué pasa si realmente queremos representar datos en una tabla? React Virtualized también lo tiene cubierto en ese frente. En este caso, haremos uso de Table
y Column
componentes que vienen integrados en React Virtualized.
Así es como pondríamos esos componentes en uso en nuestro componente principal de la aplicación:
class App extends React.Component {
render() {
return (
<div>
<h2>Details</h2>
<Table
width={500}
height={300}
headerHeight={20}
rowHeight={40}
rowCount={this.props.data.length}
rowGetter={({ index }) => this.props.data[index]}
>
<Column
label="Username"
dataKey='username'
width={100}
/>
<Column
width={200}
label="Email"
dataKey='email'
/>
</Table>
</div>
);
}
}
El Table
El componente acepta los siguientes parámetros:
width
: El ancho de la mesa.height
: La altura de la mesa.headerHeight
: La altura del encabezado de la tabla.rowHeight
: La altura de una fila dado su índice.rowCount
: Este es el número inicial de filas que queremos en la tabla. Es igual a la forma en que definimos el número de registros con los que queríamos comenzar en elList
ejemplo de componente.rowGetter
: Esto devuelve los datos de una fila específica por su índice.
Si echa un vistazo a la Column
componente, notará que ponemos un dataKey
parámetro a utilizar. Eso pasa los datos para cada columna que llamamos en el dataKey
, que recibe un identificador único para esos datos. Recuerda que en la función donde creamos nuestros datos aleatorios, hacemos uso de dos teclas; username
y email
. Por eso tenemos la dataKey
de una columna establecida como username
y el otro conjunto como email
.
En conclusión
Con suerte, este tutorial le dará una buena idea de lo que React Virtualized es capaz de hacer, cómo puede hacer que la renderización de grandes conjuntos de datos en listas y tablas sea súper rápida, y cómo usarlo en un proyecto.
Aquí solo hemos arañado la superficie. La biblioteca es capaz de manejar muchos otros casos de uso, como generar marcadores de posición para los registros de datos en el desplazamiento, un componente de carga infinita para buscar y almacenar datos en caché en tiempo real, un método para permitir que las teclas de flecha naveguen por los datos y una cuadrícula resbaladiza y diseños de mampostería que ni siquiera cubrimos aquí.
¡Eso debería darte mucho con qué jugar!
Además, el paquete está altamente mantenido. De hecho, puede unirse al grupo de Slack para mantenerse al día con el proyecto, contribuir a él y, en general, conectarse con otras personas.
También vale la pena señalar que React Virtualized tiene su propia etiqueta en StackOverflow y que puede ser un buen recurso para encontrar preguntas que otras personas han hecho al respecto, o incluso publicar sus propias preguntas.
Ah, y si ha utilizado React Virtualized en un proyecto, ¡nos encantaría saberlo! Compártelo con nosotros en los comentarios con algunas notas sobre cómo lo abordaste o qué aprendiste de él.