Operaciones de datos remotas React Grid
De forma predeterminada, IgrGrid
utiliza su propia lógica para realizar operaciones de datos.
Puede realizar estas tareas de forma remota y enviar los datos resultantes a IgrGrid
aprovechando ciertas entradas y eventos, que están expuestos por IgrGrid
.
Un diseño popular para escenarios que requieren recuperar datos por fragmentos desde un punto final es el llamado desplazamiento infinito. Para las cuadrículas de datos, se caracteriza por un aumento continuo de los datos cargados provocado por el desplazamiento del usuario final hasta el final. Los siguientes párrafos explican cómo puede utilizar la API disponible para lograr fácilmente un desplazamiento infinito en IgrGrid
.
Para implementar el desplazamiento infinito, debes recuperar los datos en fragmentos. Los datos que ya se han obtenido deben almacenarse localmente y hay que determinar la longitud de un fragmento y cuántos fragmentos hay. También debe realizar un seguimiento del último índice de fila de datos visible en la cuadrícula. De esta manera, utilizando las propiedades StartIndex
y ChunkSize
, puede determinar si el usuario se desplaza hacia arriba y debe mostrarle los datos ya obtenidos o si se desplaza hacia abajo y debe obtener más datos desde el punto final.
Lo primero que hay que hacer es obtener el primer fragmento de los datos. Establecer la propiedad es importante, ya que permite que la totalItemCount
cuadrícula ajuste el tamaño correcto de su barra de desplazamiento.
Además, debe suscribirse a la salida, de modo que pueda proporcionar los datos que necesita la DataPreLoad
cuadrícula cuando intenta mostrar un fragmento diferente, en lugar del cargado actualmente. En el controlador de eventos, debe determinar si desea capturar nuevos datos o devolver datos que ya están almacenados en caché localmente.
const DATA_URL: string =
"https://services.odata.org/V4/Northwind/Northwind.svc/Products" ;
const cachedData = <any >[];
let prevRequestChunk: number = 0 ;
export async function loadDataForPage (
page: number ,
pageSize: number ,
callback?: (args: any ) => void
) : Promise <void > {
const url = buildDataUrl(page, pageSize);
const response = await fetch(url);
const data = await response.json();
const startIndex = (page - 1 ) * pageSize;
updateData(data, startIndex);
callback({data});
}
export function getCachedData (virtualizationArgs: {startIndex: number , chunkSize: number } ) {
const virtArgsEndIndex = virtualizationArgs.startIndex + virtualizationArgs.chunkSize;
let data = [];
if (virtArgsEndIndex > cachedData.length) {
data = cachedData.slice(cachedData.length - prevRequestChunk + 1 );
} else {
data = cachedData.slice(virtualizationArgs.startIndex, virtArgsEndIndex);
prevRequestChunk = virtualizationArgs.chunkSize;
}
return data;
}
function buildDataUrl (page: number , pageSize: number ): string {
let baseQueryString = `${DATA_URL} ?$count=true&` ;
const skip = (page - 1 ) * pageSize;
const pageQuery = `$skip=${skip} &$top=${pageSize} ` ;
baseQueryString += pageQuery;
return baseQueryString;
}
function updateData (data: any , startIndex: number ) {
for (let i=0 ; i< data.value.length; i++) {
cachedData[i+startIndex] = data.value[i];
}
}
ts コピー import React , { useEffect, useRef, useState } from 'react' ;
import ReactDOM from 'react-dom/client' ;
import './index.css' ;
import { IgrForOfStateEventArgs, IgrGridModule } from "@infragistics/igniteui-react-grids" ;
import { IgrGrid, IgrColumn } from "@infragistics/igniteui-react-grids" ;
import { loadDataForPage, getCachedData } from './NwindService' ;
import "@infragistics/igniteui-react-grids/grids/combined" ;
import "@infragistics/igniteui-react-grids/grids/themes/light/bootstrap.css" ;
const mods : any [] = [
IgrGridModule
];
mods.forEach((m) => m.register());
export default function App() {
let pageSize = 10 ;
let page = 1 ;
let totalPageCount = 0 ;
let totalItems = 0 ;
const gridRef = useRef<IgrGrid > (null );
useEffect(() => {
gridRef.current.isLoading = true ;
const dataViewSize = 9.6 ;
pageSize = Math.floor(dataViewSize * 1.5 );
loadDataForPage(page,pageSize, (request) => {
if (request.data) {
gridRef.current.data = getCachedData({startIndex: 0 , chunkSize: 10 });
gridRef.current.totalItemCount = page * pageSize;
totalItems = request.data['@odata.count' ];
totalPageCount = Math.ceil(totalItems / pageSize);
gridRef.current.isLoading = false ;
}
});
}, [])
function handlePreLoad(grid: IgrGrid, e: IgrForOfStateEventArgs) {
const isLastChunk = grid.totalItemCount === e.detail.startIndex + e.detail.chunkSize;
if (isLastChunk) {
if (totalPageCount === page) {
grid.data = getCachedData(e.detail);
return ;
}
page++;
grid.isLoading = true ;
loadDataForPage(page, pageSize, (request) => {
if (request.data) {
grid.totalItemCount = Math.min(page * pageSize, totalItems);
grid.data = getCachedData(e.detail);
grid.isLoading = false ;
}
})
} else {
grid.data = getCachedData(e.detail);
}
}
return (
<>
<div className ="container sample" >
<div className ="container fill" >
<IgrGrid
autoGenerate ="false" dataPreLoad ={handlePreLoad}
ref ={gridRef} height ='480px' width ='100%' >
<IgrColumn field ="ProductID" header ="Product ID" >
</IgrColumn >
<IgrColumn field ="ProductName" header ="Product Name" >
</IgrColumn >
<IgrColumn field ="UnitsInStock" header ="Units In Stock" dataType ="number" >
</IgrColumn >
<IgrColumn field ="UnitPrice" header ="Units Price" dataType ="number" >
</IgrColumn >
<IgrColumn field ="QuantityPerUnit" >
</IgrColumn >
<IgrColumn field ="ReorderLevel" data-type ="number" header-classes ="headerAlignSyle" >
</IgrColumn >
</IgrGrid >
</div >
</div >
</>
);
}
const root = ReactDOM.createRoot (document.getElementById('root' ));
root.render (<App /> );
tsx コピー
.contextmenu {
position : absolute;
width : 180px ;
background : white;
display : flex;
cursor : context-menu;
flex-direction : column;
box-shadow : 0 1px 3px 0 rgba (0 , 0 , 0 , 0.2 ), 0 1px 1px 0 rgba (0 , 0 , 0 , 0.14 ), 0 2px 1px -1px rgba (0 , 0 , 0 , 0.12 );
z-index : 9999 ;
font-size : 0.75rem ;
font-weight : 650 ;
}
.item {
padding : 10px ;
display : flex;
}
.item :hover {
background :rgb (204 , 203 , 203 );
}
.icon {
vertical-align : middle;
margin-bottom : 5px ;
margin-right : 5px ;
}
.selected-data-area {
overflow-y : auto;
width : 50% ;
box-shadow : 0 1px 3px 0 rgba (0 , 0 , 0 , 0.2 ), 0 1px 1px 0 rgba (0 , 0 , 0 , 0.14 ), 0 2px 1px -1px rgba (0 , 0 , 0 , 0.12 );
margin-left : 10px ;
}
.wrapper {
margin : 10px ;
display : flex;
justify-content : space-evenly;
}
css コピー
¿Te gusta este ejemplo? Obtén acceso a nuestro kit de herramientas completo Ignite UI for React y comienza a crear tus propias aplicaciones en minutos. Descárgalo gratis.
Localización remota
La función de localización puede funcionar con datos remotos. Para demostrar esto, primero declaremos que nuestro servicio será responsable de la obtención de datos. Necesitaremos el recuento de todos los elementos de datos para poder calcular el recuento de páginas. Esta lógica se agregará a nuestro servicio.
const CUSTOMERS_URL = `https:
export class RemoteService {
public static getDataWithPaging(pageIndex?: number , pageSize?: number ) {
return fetch(this .buildUrl(CUSTOMERS_URL, pageIndex, pageSize))
.then((result) => result.json());
}
private static buildUrl(baseUrl: string , pageIndex?: number , pageSize?: number ) {
let qS = "" ;
if (baseUrl) {
qS += `${baseUrl}`;
}
if (pageIndex !== undefined ) {
qS += `?pageIndex=${pageIndex}`;
if (pageSize !== undefined ) {
qS += `&size=${pageSize}`;
}
} else if (pageSize !== undefined ) {
qS += `?perPage=${pageSize}`;
}
return `${qS}`;
}
}
tsx
Después de declarar el servicio, debemos crear un componente, que será responsable de la construcción y la IgrGrid
suscripción de datos.
<IgrGrid
ref ={grid}
data ={data}
pagingMode ={GridPagingMode.Remote}
primaryKey ="customerId"
height ="600px"
isLoading ={isLoading}
>
<IgrPaginator
perPage ={perPage}
ref ={paginator}
pageChange ={onPageNumberChange}
perPageChange ={onPageSizeChange} >
</IgrPaginator >
<IgrColumn field ="customerId" hidden ={true} > </IgrColumn >
<IgrColumn field ="companyName" header ="Company Name" > </IgrColumn >
<IgrColumn field ="contactName" header ="Contact Name" > </IgrColumn >
<IgrColumn field ="contactTitle" header ="Contact Title" > </IgrColumn >
<IgrColumn field ="address.country" header ="Country" > </IgrColumn >
<IgrColumn field ="address.phone" header ="Phone" > </IgrColumn >
</IgrGrid >
tsx
A continuación, configure el estado:
const grid = useRef<IgrGrid > (null );
const paginator = useRef<IgrPaginator > (null );
const [data , setData ] = useState([]);
const [page , setPage ] = useState(0 );
const [perPage , setPerPage ] = useState(15 );
const [isLoading , setIsLoading ] = useState(true );
useEffect(() => {
loadGridData(page, perPage);
}, [page, perPage]);
tsx
y finalmente configure el método para cargar los datos:
function loadGridData(pageIndex?: number , pageSize?: number ) {
setIsLoading(true );
RemoteService.getDataWithPaging(pageIndex, pageSize)
.then((response: CustomersWithPageResponseModel) => {
setData(response.items);
setIsLoading(false );
paginator.current.totalRecords = response.totalRecordsCount;
})
.catch ((error) => {
console.error(error.message);
setData([]);
setIsLoading(false );
})
}
tsx
Para obtener más información, consulte la muestra completa a continuación:
Demostración de paginación remota de cuadrícula
const URL = `https://data-northwind.indigo.design/` ;
export class RemoteService {
public getData(dataState: any , index?: number , perPage?: number ): any {
return fetch(this .buildUrl(dataState, index, perPage))
.then((result ) => result.json());
}
private buildUrl (dataState: any , index?: number , perPage?: number ) {
let qS = "" ;
if (dataState) {
qS += `${dataState.key} ` ;
}
if (index !== undefined ) {
qS += `?index=${index} ` ;
if (perPage !== undefined ) {
qS += `&perPage=${perPage} ` ;
}
} else if (perPage !== undefined ) {
qS += `?perPage=${perPage} ` ;
}
return `${URL} ${qS} ` ;
}
public getDataLength(dataState: any ): Promise <number > {
return fetch(this .buildUrl(dataState))
.then((result ) => result.json())
.then((data ) => data.length);
}
}
ts コピー import React , { useEffect, useRef, useState } from "react" ;
import ReactDOM from "react-dom/client" ;
import "./index.css" ;
import { IgrGrid, IgrPaginator, IgrGridModule } from "@infragistics/igniteui-react-grids" ;
import { IgrColumn } from "@infragistics/igniteui-react-grids" ;
import "@infragistics/igniteui-react-grids/grids/combined" ;
import "@infragistics/igniteui-react-grids/grids/themes/light/bootstrap.css" ;
import { RemoteService } from "./RemotePagingService" ;
IgrGridModule.register();
export default function App() {
let data = [];
const grid = useRef<IgrGrid > (null );
const paginator = useRef<IgrPaginator > (null );
const remoteServiceInstance = new RemoteService();
let [page ] = useState(0 );
let [perPage , setPerPage ] = useState(15 );
useEffect(() => {
if (paginator.current) {
setPerPage(15 );
grid.current.isLoading = true ;
}
grid.current.isLoading = true ;
loadData('Customers' );
}, [page, 15 ]);
function loadData(dataKey: string ) {
const dataState = { key: dataKey };
grid.current.isLoading = true ;
remoteServiceInstance.getDataLength(dataState).then((length: number ) => {
paginator.current.totalRecords = length;
});
remoteServiceInstance.getData(dataState).then((data: any []) => {
grid.current.isLoading = false ;
grid.current.data = data;
grid.current.markForCheck();
});
}
function paginate(pageArgs: number ) {
page = pageArgs;
const skip = page * perPage;
const top = perPage;
remoteServiceInstance.getData({ key: 'Customers' }, skip, top).then((incData:any )=> {
data = incData;
grid.current.isLoading = false ;
grid.current.markForCheck();
});
}
return (
<div className ="container sample ig-typography" >
<div className ="container fill" >
<IgrGrid
ref ={grid}
primaryKey ="customerId"
height ="600px"
>
<IgrPaginator
perPage ="15"
ref ={paginator}
pageChange ={(evt: { page: number }) => paginate(evt.page)}
perPageChange={() => paginate(0 )}></IgrPaginator >
<IgrColumn field ="customerId" hidden ={true} > </IgrColumn >
<IgrColumn field ="companyName" header ="Company Name" > </IgrColumn >
<IgrColumn field ="contactName" header ="Contact Name" > </IgrColumn >
<IgrColumn field ="contactTitle" header ="Contact Title" > </IgrColumn >
<IgrColumn field ="address.country" header ="Country" > </IgrColumn >
<IgrColumn field ="address.phone" header ="Phone" > </IgrColumn >
</IgrGrid >
</div >
</div >
);
}
const root = ReactDOM.createRoot (document.getElementById("root" ));
root.render (<App /> );
tsx コピー
y, por último, configura el comportamiento de las RowIslands:
Problemas conocidos y limitaciones
Cuando la grilla no tiene PrimaryKey
configurada y los escenarios de datos remotos están habilitados (al paginar, ordenar, filtrar y desplazar solicitudes de activación a un servidor remoto para recuperar los datos que se mostrarán en la grilla), una fila perderá el siguiente estado después de un dato. solicitud completa:
Selección de fila
Fila Expandir/contraer
Edición de filas
Fijación de filas
Referencias de API
Recursos adicionales
Nuestra comunidad es activa y siempre da la bienvenida a nuevas ideas.