You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何结合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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 17:16:09