React中MaterialTable首次加载Redux远程数据失败问题求助
Hey there! Let's dig into why your MaterialTable isn't loading data properly with Redux for server-side pagination. I've spotted the core issue and put together a fixed solution for you.
The Root Problem
Your current code calls getVehichles in the MaterialTable data function and immediately resolves the promise. But Redux's async data flow takes time—when you resolve, the this.props.vehichles.rows hasn't been updated yet (the API request is still in flight). Plus, the data function runs on initial render before Redux has finished initializing, so you're loading empty data by default.
Fixed Solution with Step-by-Step Changes
Let's restructure the code to sync MaterialTable's pagination state with Redux properly:
1. Updated VehicleList Component (Fixed Spelling & Logic)
import React, { Component } from "react"; import Button from "@material-ui/core/Button"; import Grid from "@material-ui/core/Grid"; import Box from "@material-ui/core/Box"; import { connect } from "react-redux"; import MaterialTable from "material-table"; import { getVehicles } from "../../store/actions/vehicleActions"; class VehicleActionButtons extends Component { constructor(props) { super(props); this.tableRef = React.createRef(); // Track pagination state locally to sync with table this.state = { currentPage: 0, pageSize: 10 // Match MaterialTable's default page size }; } componentDidMount() { // Load initial data when component mounts const { currentPage, pageSize } = this.state; this.props.getVehicles({ page: currentPage, pageSize }); } // Trigger data fetch when page changes handlePageChange = (newPage) => { this.setState({ currentPage: newPage }, () => { const { currentPage, pageSize } = this.state; this.props.getVehicles({ page: currentPage, pageSize }); }); }; // Reset page to 0 and fetch data when rows per page changes handleRowsPerPageChange = (newPageSize) => { this.setState({ pageSize: newPageSize, currentPage: 0 }, () => { const { currentPage, pageSize } = this.state; this.props.getVehicles({ page: currentPage, pageSize }); }); }; refreshTableData = () => { if (this.tableRef.current) { this.tableRef.current.onQueryChange(); } }; render() { const { vehicles } = this.props; const { currentPage, pageSize } = this.state; return ( <Box m={6}> <Grid container> <Grid item xs> <Box m={2}> <MaterialTable tableRef={this.tableRef} columns={vehicles.columns} // Resolve data directly from Redux props (updated when state changes) data={() => Promise.resolve({ data: vehicles.rows, page: currentPage, totalCount: vehicles.totalCount }) } title="Vehicle List" options={{ pagination: true, pageSize, pageSizeOptions: [5, 10, 20], serverSide: true }} // Bind pagination callbacks to trigger Redux actions onChangePage={this.handlePageChange} onChangeRowsPerPage={this.handleRowsPerPageChange} // Show loading state while data is being fetched isLoading={!vehicles.loaded} /> </Box> </Grid> </Grid> </Box> ); } } const mapStateToProps = (state) => { return { vehicles: state.vehicle }; }; const mapDispatchToProps = (dispatch) => { return { getVehicles: (query) => dispatch(getVehicles(query)) }; }; export default connect(mapStateToProps, mapDispatchToProps)(VehicleActionButtons);
2. Updated Action Code (Cleaner Async Logic)
import axios from 'axios'; export const getVehicles = (query) => { return async (dispatch) => { dispatch({ type: "GETTING_VEHICLES_LIST"}); try { // Use template literals for cleaner URL construction const url = `http://my-json-server.typicode.com/mksrivastava/zwe/rows?_limit=${query.pageSize}&_page=${query.page + 1}`; const resp = await axios.get(url); dispatch({ type: "GET_VEHICLES_LIST", data: resp.data, totalCount: +resp.headers['x-total-count'] }); } catch (error) { dispatch({ type: "GET_VEHICLES_LIST_ERROR", error: error.message || "Unexpected Error!!!" }); } }; }
3. Updated Reducer Code (Spelling Fixes & Clear State Updates)
const initState = { rows: [], columns: [ { title: "Vehicle No", field: "vehicleNo" }, { title: "Date of Reg", field: "dateOfReg", type: "date" }, { title: "Status of Reg", field: "statusOfReg" }, { title: "Engine Type", field: "EngineType" }, { title: "Modal Year", field: "year" }, ], totalCount: 0, loaded: false, error: null }; const vehicleReducer = (state = initState, action) => { switch (action.type) { case "GETTING_VEHICLES_LIST": return { ...state, loaded: false, error: null }; case "GET_VEHICLES_LIST": return { ...state, rows: action.data, totalCount: action.totalCount, loaded: true }; case "GET_VEHICLES_LIST_ERROR": return { ...state, loaded: true, error: action.error }; default: return state; } }; export default vehicleReducer;
Key Improvements
- Unified Spelling: Fixed
vehichle→vehicleeverywhere to avoid state mapping bugs. - Controlled Pagination: Used MaterialTable's
onChangePageandonChangeRowsPerPageto trigger data fetches, making the flow predictable. - Loading Feedback: Added
isLoadingto show users when data is being fetched. - Cleaner Async Code: Used
async/awaitin actions for readability, and passed only necessary data to the reducer.
This setup ensures your table loads initial data on mount, updates automatically when Redux state changes, and syncs perfectly with pagination controls.
内容的提问来源于stack exchange,提问作者Manish Kumar Srivastava

