如何结合useEffect与RTK Query更新Reducer中的状态?
问题分析与解决
核心问题
你遇到的employeesList变成undefined的原因很明确:
组件挂载时useEffect立刻执行,这时候API请求还没完成,data的值是undefined,执行dispatch(storeEmployees(data))后,直接把初始的空数组覆盖成了undefined。
另外,其实完全没必要把RTK Query获取的数据再存到自定义Reducer里——RTK Query本身已经帮你处理了数据缓存、加载/错误状态管理,额外存一份属于冗余操作,反而容易出问题。
解决方案
方案1:直接用RTK Query的数据(推荐,简化代码)
删掉自定义的employeesSlice,直接使用useGetEmployeesQuery返回的data,同时处理加载、错误状态避免报错:
import React from 'react'; import { Table, Spinner, Alert } from "react-bootstrap"; import { useGetEmployeesQuery } from "./employeesApiSlice"; function Employees(){ const { data: employeesList, isLoading, isSuccess, isError, error } = useGetEmployeesQuery(); // 加载状态 if (isLoading) return <Spinner animation="border" />; // 错误状态 if (isError) return <Alert variant="danger">{error?.data?.message || '获取员工数据失败'}</Alert>; return ( <Table size='sm' striped bordered hover responsive> <thead> <tr> <th>No</th> <th>First Name</th> <th>Last Name</th> <th>Position</th> <th>Record Created</th> <th>Record Updated</th> </tr> </thead> <tbody> {isSuccess && employeesList?.map((employee, i) => ( <tr key={employee.id /* 别用索引当key,用唯一ID */}> <td>{i+1}</td> <td>{employee.firstName}</td> <td>{employee.lastName}</td> <td>{employee.position}</td> <td>{employee.recordCreatedAt}</td> <td>{employee.recordUpdatedAt}</td> </tr> ))} </tbody> </Table> ) } export default Employees;
方案2:一定要存到自定义Reducer?修正useEffect逻辑
如果确实需要把数据同步到自己的slice,要确保只在数据成功返回时才dispatch:
import React, { useEffect } from 'react'; import { Table, Spinner, Alert } from "react-bootstrap"; import { useDispatch, useSelector } from "react-redux"; import { useGetEmployeesQuery } from "./employeesApiSlice"; import { storeEmployees } from "./employeesSlice"; function Employees(){ const dispatch = useDispatch(); const { data, isLoading, isSuccess, isError, error } = useGetEmployeesQuery(); const { employeesList } = useSelector(state => state.employees); // 依赖加data和isSuccess,确保数据成功返回时才更新 useEffect(() => { if (isSuccess && data) { dispatch(storeEmployees(data)); } }, [data, isSuccess, dispatch]); if (isLoading) return <Spinner animation="border" />; if (isError) return <Alert variant="danger">{error?.data?.message || '获取员工数据失败'}</Alert>; return ( <Table size='sm' striped bordered hover responsive> <thead> <tr> <th>No</th> <th>First Name</th> <th>Last Name</th> <th>Position</th> <th>Record Created</th> <th>Record Updated</th> </tr> </thead> <tbody> {employeesList?.map((employee, i) => ( <tr key={employee.id}> <td>{i+1}</td> <td>{employee.firstName}</td> <td>{employee.lastName}</td> <td>{employee.position}</td> <td>{employee.recordCreatedAt}</td> <td>{employee.recordUpdatedAt}</td> </tr> ))} </tbody> </Table> ) } export default Employees;
额外提示
- 别用数组索引当
key,尽量用数据里的唯一ID(比如employee.id),避免列表更新时出现渲染异常。 - RTK Query的
keepUnusedDataFor已经设置了缓存时间,直接用它的状态足够满足大部分场景,没必要重复维护状态。
内容的提问来源于stack exchange,提问作者noBoom
相关产品推荐
相关产品推荐

