React menu component, update state, correctly but the data in the menu component cannot be refreshed (using ant-design-pro)

problem description

use the ant-design-pro template. https://github.com/ant-design.

if you want to request menu data from the background, the data can be obtained correctly, and the state changes are also correct, but when the page is rendered, the data cannot be loaded into the menu component .

get the menu data section, which I write to the componentWillMount function.

class BasicLayout extends React.PureComponent {
    

  componentWillMount() {
    const { dispatch } = this.props;
    dispatch({
      type: "user/fetchMenu",
    });
  }

    
}

but log in again, because you already have menu data in state, so you can load the menu and data correctly.

the environmental background of the problems and what methods you have tried

I noticed that BasicLayout, a big component, and SideMenu, both components, use PureComponent,. I wonder if it has anything to do with this?

related codes

/ / Please paste the code text below (do not replace the code with pictures)

import React, { Fragment } from "react";
import PropTypes from "prop-types";
import { Icon, Layout, message } from "antd";
import DocumentTitle from "react-document-title";
import { connect } from "dva";
import { Redirect, Route, routerRedux, Switch } from "dva/router";
import { ContainerQuery } from "react-container-query";
import classNames from "classnames";
import pathToRegexp from "path-to-regexp";
import { enquireScreen, unenquireScreen } from "enquire-js";
import GlobalHeader from "../components/GlobalHeader";
import GlobalFooter from "../components/GlobalFooter";
import SiderMenu from "../components/SiderMenu";
import NotFound from "../routes/Exception/404";
import { getRoutes } from "../utils/utils";
import Authorized from "../utils/Authorized";
import { getMenuData } from "../common/menu";
import logo from "../assets/logo.svg";

const { Content, Header, Footer } = Layout;
const { AuthorizedRoute, check } = Authorized;

/**
 * .
 */
const redirectData = [];
const getRedirect = item => {
  if (item && item.children) {
    if (item.children[0] && item.children[0].path) {
      redirectData.push({
        from: `${item.path}`,
        to: `${item.children[0].path}`,
      });
      item.children.forEach(children => {
        getRedirect(children);
      });
    }
  }
};
getMenuData().forEach(getRedirect);

/**
 * 
 * @param {Object} menuData 
 * @param {Object} routerData 
 */
const getBreadcrumbNameMap = (menuData, routerData) => {
  const result = {};
  const childResult = {};
  for (const i of menuData) {
    if (!routerData[i.path]) {
      result[i.path] = i;
    }
    if (i.children) {
      Object.assign(childResult, getBreadcrumbNameMap(i.children, routerData));
    }
  }
  return Object.assign({}, routerData, result, childResult);
};

const query = {
  "screen-xs": {
    maxWidth: 575,
  },
  "screen-sm": {
    minWidth: 576,
    maxWidth: 767,
  },
  "screen-md": {
    minWidth: 768,
    maxWidth: 991,
  },
  "screen-lg": {
    minWidth: 992,
    maxWidth: 1199,
  },
  "screen-xl": {
    minWidth: 1200,
    maxWidth: 1599,
  },
  "screen-xxl": {
    minWidth: 1600,
  },
};

let isMobile;
enquireScreen(b => {
  isMobile = b;
});

class BasicLayout extends React.Component {
  static childContextTypes = {
    location: PropTypes.object,
    breadcrumbNameMap: PropTypes.object,
  };

  state = {
    isMobile,
  };

  getChildContext() {
    const { location, routerData, menu } = this.props;
    return {
      location,
      breadcrumbNameMap: getBreadcrumbNameMap(menu, routerData), // getMenuData()
    };
  }

  componentWillMount() {
    const { dispatch } = this.props;
    dispatch({
      type: "user/fetchMenu",
    });
  }

  componentDidMount() {
    this.enquireHandler = enquireScreen(mobile => {
      this.setState({
        isMobile: mobile,
      });
    });
    const { dispatch } = this.props;
    dispatch({
      type: "user/fetchCurrent",
    });
  }

  componentWillUnmount() {
    unenquireScreen(this.enquireHandler);
  }

  getPageTitle() {
    const { routerData, location } = this.props;
    const { pathname } = location;
    let title = "";
    let currRouterData = null;
    // match params path
    Object.keys(routerData).forEach(key => {
      if (pathToRegexp(key).test(pathname)) {
        currRouterData = routerData[key];
      }
    });
    if (currRouterData && currRouterData.name) {
      title = `${currRouterData.name} - `;
    }
    return title;
  }

  getBaseRedirect = () => {
    // According to the url parameter to redirect
    // , url  redirect 
    const urlParams = new URL(window.location.href);

    const redirect = urlParams.searchParams.get("redirect");
    // Remove the parameters in the url
    if (redirect) {
      urlParams.searchParams.delete("redirect");
      window.history.replaceState(null, "redirect", urlParams.href);
    } else {
      const { routerData } = this.props;
      // get the first authorized route path in routerData
      const authorizedPath = Object.keys(routerData).find(
        item => check(routerData[item].authority, item) && item !== "/"
      );
      return authorizedPath;
    }
    return redirect;
  };

  handleMenuCollapse = collapsed => {
    const { dispatch } = this.props;
    dispatch({
      type: "global/changeLayoutCollapsed",
      payload: collapsed,
    });
  };

  handleNoticeClear = type => {
    message.success(`${type}`);
    const { dispatch } = this.props;
    dispatch({
      type: "global/clearNotices",
      payload: type,
    });
  };

  handleMenuClick = ({ key }) => {
    const { dispatch } = this.props;
    if (key === "triggerError") {
      dispatch(routerRedux.push("/exception/trigger"));
      return;
    }
    if (key === "logout") {
      dispatch({
        type: "login/logout",
      });
    }
  };

  handleNoticeVisibleChange = visible => {
    const { dispatch } = this.props;
    if (visible) {
      dispatch({
        type: "global/fetchNotices",
      });
    }
  };

  render() {
    const {
      currentUser,
      collapsed,
      fetchingNotices,
      notices,
      routerData,
      match,
      location,
      menu,
    } = this.props;
    const { isMobile: mb } = this.state;
    const bashRedirect = this.getBaseRedirect();
    const layout = (
      <Layout>
        <SiderMenu
          logo={logo}
          // Authorized,403
          // If you do not have the Authorized parameter
          // you will be forced to jump to the 403 interface without permission
          Authorized={Authorized}
          menuData={menu} // JSON.parse(localStorage.getItem("menu"))
          collapsed={collapsed}
          location={location}
          isMobile={mb}
          onCollapse={this.handleMenuCollapse}
        />
        <Layout>
          <Header style={{ padding: 0 }}>
            <GlobalHeader
              logo={logo}
              currentUser={currentUser}
              fetchingNotices={fetchingNotices}
              notices={notices}
              collapsed={collapsed}
              isMobile={mb}
              onNoticeClear={this.handleNoticeClear}
              onCollapse={this.handleMenuCollapse}
              onMenuClick={this.handleMenuClick}
              onNoticeVisibleChange={this.handleNoticeVisibleChange}
            />
          </Header>
          <Content style={{ margin: "24px 24px 0", height: "100%" }}>
            <Switch>
              {redirectData.map(item => (
                <Redirect key={item.from} exact from={item.from} to={item.to} />
              ))}
              {getRoutes(match.path, routerData).map(item => (
                <AuthorizedRoute
                  key={item.key}
                  path={item.path}
                  component={item.component}
                  exact={item.exact}
                  authority={item.authority}
                  redirectPath="/exception/403"
                />
              ))}
              <Redirect exact from="/" to={bashRedirect} />
              <Route render={NotFound} />
            </Switch>
          </Content>
          <Footer style={{ padding: 0 }}>
            <GlobalFooter
              links={[
                {
                  key: "Jenkins",
                  title: "Jenkins",
                  href: "http://10.124.210.64:8080",
                  blankTarget: true,
                },
                {
                  key: "gitlab",
                  title: <Icon type="gitlab" />,
                  href: "http://10.124.210.40:8080/",
                  blankTarget: true,
                },
                {
                  key: "Marathon",
                  title: "Marathon",
                  href: "http://10.124.210.41:8080/ui/-sharp/apps",
                  blankTarget: true,
                },
              ]}
              copyright={
                <Fragment>
                  Copyright <Icon type="copyright" /> 2018 -
                </Fragment>
              }
            />
          </Footer>
        </Layout>
      </Layout>
    );

    return (
      <DocumentTitle title={this.getPageTitle()}>
        <ContainerQuery query={query}>
          {params => <div className={classNames(params)}>{layout}</div>}
        </ContainerQuery>
      </DocumentTitle>
    );
  }
}

function mapStateToProps(state) {
  return {
    ...state,
    menu: state.user.menu,
    currentUser: state.user.currentUser,
    collapsed: state.global.collapsed,
    fetchingNotices: state.loading.effects["global/fetchNotices"],
    notices: state.global.notices,
  };
}

export default connect(mapStateToProps)(BasicLayout);

what result do you expect? What is the error message actually seen?

Mar.31,2021

if your menu data is an object, don't use PureComponent , use Component


the official website suggests that the api, for obtaining data should be placed in the componentDidMount life cycle, and in version 16.4.1, it seems that the componentWillMount life cycle has been abolished. You can make sure < SiderMenu

      logo={logo}
      // Authorized,403
      // If you do not have the Authorized parameter
      // you will be forced to jump to the 403 interface without permission
      Authorized={Authorized}
      menuData={menu} // JSON.parse(localStorage.getItem('menu'))
      collapsed={collapsed}
      location={location}
      isMobile={mb}
      onCollapse={this.handleMenuCollapse}
    />
    menu

try withRouter , I'm not sure if it works.

export default withRouter(connect(mapStateToProps)(BasicLayout));

mentioned issue, on github and later found the answer
https://github.com/ant-design.

.
  • Database loading problem of ant design pro menu

    java programmers use the project Ant Financial Services Group ant design pro ((hereinafter referred to as pro). Everyone who has used it knows that the menu of the original pro project is defined by a file. I would like to ask how to load the menu json f...

    Mar.18,2021
  • Antd design pro dispatch infinite loop

    antd design pro dispatch infinite loop related codes There is a button in table code as follows <span className={Style.opt} style={{ color: record.display === 1 ? notClickColor : canClickColor, cursor: record.display === 1 ? notClic...

    Jun.02,2022
MySQL Query : SELECT * FROM `codeshelper`.`v9_news` WHERE status=99 AND catid='6' ORDER BY rand() LIMIT 5
MySQL Error : Disk full (/tmp/#sql-temptable-64f5-1e993b7-5c558.MAI); waiting for someone to free some space... (errno: 28 "No space left on device")
MySQL Errno : 1021
Message : Disk full (/tmp/#sql-temptable-64f5-1e993b7-5c558.MAI); waiting for someone to free some space... (errno: 28 "No space left on device")
Need Help?