如何结合React Redux实现Datatables.net的服务端分页?
结合React Redux实现Datatables.net服务端分页方案
核心思路是启用Datatables的服务端处理模式,让Datatables的分页操作触发你的Redux Action,而非直接发起AJAX请求。同时同步Redux中存储的总条目数、当前页数据到Datatables,确保分页控件能正确渲染。下面是具体实现步骤:
步骤1:调整父组件,传递必要参数给Table组件
首先确保父组件从Redux中获取总条目数,并把数据请求Action、总条目数一起传递给Table组件:
import React from 'react' import { bindActionCreators } from 'redux' import { connect } from 'react-redux' import { doList } from './your-action-file' import Table from './Table' import predefinedColums from './your-columns' const ParentComponent = (props) => { return ( <div> {/* 无需手动触发请求,Datatables会自动处理分页请求 */} <Table data={props.list} columns={predefinedColums} totalCount={props.totalCount} fetchData={props.doList} title="Your Table Title" /> </div> ) } const mapStateToProps = (state) => { return ({ list: state.reducer.list, totalCount: state.reducer.totalCount, // 从Redux中读取总条目数 }) } const mapDispatchToProps = dispatch => bindActionCreators( { doList }, dispatch ) export default connect(mapStateToProps, mapDispatchToProps)(ParentComponent)
步骤2:修改Table组件,配置Datatables服务端模式
更新Table组件,开启serverSide: true,并自定义ajax回调触发Redux Action,同时同步数据状态:
import React, { useEffect, useRef } from 'react' import $ from 'jquery' import 'datatables.net' import 'datatables.net-responsive' import 'datatables.net-select' import i18n from './your-i18n-config' function Table(props) { const { columns, data, title, totalCount, fetchData } = props const tableRef = useRef(null) // 使用Ref替代ID选择器,避免多实例冲突 useEffect(() => { // 销毁已有Datatables实例,避免重复初始化 if ($.fn.DataTable.isDataTable(tableRef.current)) { $(tableRef.current).DataTable().destroy() } const table = $(tableRef.current).DataTable({ retrieve: true, serverSide: true, // 关键:开启服务端处理 processing: true, // 显示加载状态提示 data: data, // 传入当前页数据 columns: columns, responsive: true, lengthMenu: [ [10, 25, 50, -1], [10, 25, 50, "All"] ], language: { emptyTable: i18n.t('emptyDataSourceMessage'), paginate: { previous: i18n.t('Previous'), next: i18n.t('Next'), first: i18n.t("First"), last: i18n.t("Last"), }, infoFiltered: i18n.t("(filtered from _MAX_ total entries)"), search: i18n.t('Search'), info: i18n.t("Showing _START_ to _END_ of _TOTAL_ entries"), infoEmpty: i18n.t("Showing 0 to 0 of 0 entries"), }, // 自定义AJAX回调,Datatables自动传递分页参数 ajax: function(dtParams, callback) { // dtParams.start = 偏移量(对应你的offset),dtParams.length = 每页条数 const requestParams = { offset: dtParams.start, limit: dtParams.length } // 触发Redux Action获取数据 fetchData(requestParams) .then(() => { // 告知Datatables请求结果,确保分页控件正确渲染 callback({ draw: dtParams.draw, // 必须返回,用于Datatables跟踪请求顺序 recordsTotal: totalCount, // 总条目数 recordsFiltered: totalCount, // 无搜索过滤时与totalCount一致 data: data // 当前页数据 }) }) .catch(err => { // 错误处理:返回空数据避免表格报错 callback({ draw: dtParams.draw, recordsTotal: 0, recordsFiltered: 0, data: [] }) }) } }) // 组件卸载时清理Datatables实例 return () => { if ($.fn.DataTable.isDataTable(tableRef.current)) { table.destroy() } } }, [columns, data, totalCount, fetchData]) return ( <div className="row"> <div className="col s12"> <div className="section section-data-tables"> <div className="card"> <div className="card-content"> <h4 className="card-title">{title}</h4> <div className="row"> <div className="col s12"> <table ref={tableRef} className="display"> <thead> <tr> {columns.map((column, key) => ( <th key={key} data-field={column.field}>{column.title}</th> ))} </tr> </thead> <tbody></tbody> <tfoot> <tr> {columns.map((column, key) => ( <th key={key} data-field={column.field}>{column.title}</th> ))} </tr> </tfoot> </table> </div> </div> </div> </div> </div> </div> </div> ) } export default Table
步骤3:更新Redux Action与Reducer,存储总条目数
确保你的API返回当前页数据和总条目数,并在Action和Reducer中处理这部分数据:
// Action示例 export const doList = (params) => async (dispatch) => { try { const response = await api.get('/your-api-endpoint', { params }) // 假设API返回格式:{ data: [...], total: 150 } dispatch({ type: 'FETCH_LIST_SUCCESS', payload: { list: response.data.data, totalCount: response.data.total } }) } catch (err) { dispatch({ type: 'FETCH_LIST_FAILURE' }) // 可添加错误提示逻辑 } } // Reducer示例 const initialState = { list: [], totalCount: 0 } const reducer = (state = initialState, action) => { switch(action.type) { case 'FETCH_LIST_SUCCESS': return { ...state, list: action.payload.list, totalCount: action.payload.totalCount } case 'FETCH_LIST_FAILURE': return { ...state, list: [] } default: return state } } export default reducer
关键注意事项
- 避免ID选择器:使用React的
useRef获取表格元素,避免多表格实例冲突。 - 同步状态:必须将Redux中的
totalCount传递给Datatables,否则分页控件无法正确计算总页数。 draw参数:必须原样返回Datatables传递的draw参数,否则分页可能出现顺序混乱。- 加载状态:开启
processing: true能在请求数据时显示加载动画,提升用户体验。
配置完成后,点击Datatables的分页按钮会自动触发Redux Action获取对应页的数据,表格会自动更新内容,分页控件也会根据总条目数正确显示。
内容的提问来源于stack exchange,提问作者Luiz Fernando da Silva
相关产品推荐
相关产品推荐

