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

React中无法显示Laravel来源动态菜单的问题求助

问题分析

你当前的写法存在核心问题:模块加载时的立即执行异步函数是异步执行的,而createSlice是同步执行的——当createSlice创建切片时,initialState还没被异步请求的结果修改,所以切片的初始状态始终是空数组。而且即使你修改了initialState变量,也不会影响已经创建的Redux切片,因为Redux的状态更新必须通过dispatch action来触发,直接修改变量根本不会同步到Redux store。

解决方案

我们需要用Redux Toolkit的异步Thunk来处理API请求,然后通过reducer更新状态。具体步骤如下:

1. 修改sideMenuSlice.ts,添加更新状态的reducer和异步Thunk

import SidebarDataFetcher from "../Pages/SidebarDataFetcher";
import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
import { RootState } from "./store";
import { icons } from "../base-components/Lucide";

export interface Menu {
  icon: keyof typeof icons;
  title: string;
  pathname?: string;
  subMenu?: Menu[];
  ignore?: boolean;
}

export interface SideMenuState {
  menu: Array<Menu | "divider">;
  loading: boolean; // 新增加载状态,方便处理加载中UI
  error: string | null; // 新增错误状态,处理请求失败情况
}

// 初始状态保留空数组,同时添加加载和错误状态
const initialState: SideMenuState = {
  menu: [],
  loading: false,
  error: null,
};

// 创建异步Thunk:负责获取侧边栏数据
export const fetchSideMenu = createAsyncThunk(
  "sideMenu/fetchSideMenu",
  async () => {
    const sidebarData = await SidebarDataFetcher();
    // 转换数据格式,和你之前的逻辑一致
    return Object.entries(sidebarData).flatMap(([key, value]) =>
      Object.entries(value).map(([subKey, subValue]) => ({
        icon: "Activity" as keyof typeof icons,
        title: subKey,
        subMenu: subValue.map((item) => ({
          icon: item.icon as keyof typeof icons,
          title: item.name,
          pathname: item.url_slug,
        })),
      }))
    );
  }
);

export const sideMenuSlice = createSlice({
  name: "sideMenu",
  initialState,
  reducers: {},
  // 处理异步Thunk的三种状态:pending(请求中)、fulfilled(成功)、rejected(失败)
  extraReducers: (builder) => {
    builder
      .addCase(fetchSideMenu.pending, (state) => {
        state.loading = true;
        state.error = null;
      })
      .addCase(fetchSideMenu.fulfilled, (state, action) => {
        state.loading = false;
        // 将获取到的数据更新到状态中
        state.menu = action.payload;
      })
      .addCase(fetchSideMenu.rejected, (state, action) => {
        state.loading = false;
        state.error = action.error.message || "加载侧边栏数据失败";
      });
  },
});

export const selectSideMenu = (state: RootState) => state.sideMenu.menu;
export const selectSideMenuLoading = (state: RootState) => state.sideMenu.loading;
export const selectSideMenuError = (state: RootState) => state.sideMenu.error;

export default sideMenuSlice.reducer;

2. 在组件中触发异步请求并使用状态

比如在你的侧边栏组件或者App根组件中:

import { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { fetchSideMenu, selectSideMenu, selectSideMenuLoading, selectSideMenuError } from "./store/sideMenuSlice";

function Sidebar() {
  const dispatch = useDispatch();
  const menu = useSelector(selectSideMenu);
  const loading = useSelector(selectSideMenuLoading);
  const error = useSelector(selectSideMenuError);

  // 组件挂载时触发数据请求
  useEffect(() => {
    dispatch(fetchSideMenu());
  }, [dispatch]);

  if (loading) {
    return <div>加载中...</div>;
  }

  if (error) {
    return <div>加载失败:{error}</div>;
  }

  // 渲染你的菜单
  return (
    <div className="sidebar">
      {menu.map((item, index) => {
        if (item === "divider") {
          return <div key={index} className="divider"></div>;
        }
        // 根据Menu类型渲染菜单项和子菜单
        return (
          <div key={index} className="menu-item">
            <span>{item.icon}</span>
            <span>{item.title}</span>
            {item.subMenu && (
              <div className="sub-menu">
                {item.subMenu.map((subItem, subIndex) => (
                  <a key={subIndex} href={subItem.pathname}>
                    {subItem.icon} {subItem.title}
                  </a>
                ))}
              </div>
            )}
          </div>
        );
      })}
    </div>
  );
}

export default Sidebar;
关键说明
  • 永远不要试图在模块加载阶段通过异步操作修改Redux的初始状态,Redux的状态更新必须通过dispatch action完成。
  • createAsyncThunk是Redux Toolkit提供的处理异步逻辑的工具,它会自动生成三个action(pending/fulfilled/rejected),我们可以在extraReducers中监听这些action来更新状态。
  • 添加loading和error状态可以让你更好地处理加载中和错误场景,提升用户体验。

内容的提问来源于stack exchange,提问作者Known Dev

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 07:52:25