繁体   English   中英

React.js:如何在渲染页面之前先运行 useEffect?

[英]React.js: How to run useEffect first before rendering page?

我正在尝试实现一个动态菜单,该菜单根据用户角色改变其结构

请参阅下面的完整代码:

import React, {
  useState,
  useLayoutEffect,
  useEffect,
  useCallback,
} from "react";
import { Drawer, IconButton, List, Avatar } from "@material-ui/core";
import {
  Inbox as InboxIcon,
  PresentToAll as PresentToAllIcon,
  ListAlt as ListAltIcon,
  Language as LanguageIcon,
  Description as DescriptionIcon,
  List as ListIcon,
  Money as MoneyIcon,
  Face as FaceIcon,
  TransferWithinAStation as TransferWithinAStationIcon,
  AttachMoney as AttachMoneyIcon,
  PersonPinCircle as PersonPinCircleIcon,
  Home as HomeIcon,
  ArrowBack as ArrowBackIcon,
  Edit as EditIcon,
  AccountBalanceWallet,
  PeopleAlt,
} from "@material-ui/icons";
import { useTheme } from "@material-ui/styles";
import { withRouter } from "react-router-dom";
import classNames from "classnames";
import useStyles from "./styles";
import SidebarLink from "./components/SidebarLink/SidebarLink";
import {
  useLayoutState,
  useLayoutDispatch,
  toggleSidebar,
} from "../../context/LayoutContext";
import Dot from "./components/Dot";
import pesonetlogo from "../../images/test-logo.png";
import { USER_PROFILE_ID_SESSION_ATTRIBUTE } from "../../services/AuthenticationService";
import ProfileMaintenanceService from "../../services/ProfileMaintenanceService";

function Sidebar({ location }) {
  var classes = useStyles();
  var theme = useTheme();

  var { isSidebarOpened, modules } = useLayoutState();
  var layoutDispatch = useLayoutDispatch();

  var [isPermanent, setPermanent] = useState(true);

  // should be in UserContext for global state
  const [profileDetails, setProfileDetails] = useState([]);
  const [profileModules, setProfileModules] = useState([]);
  // const [profileActions, setProfileActions] = useState([]);

  var structureNew = [];

  const profileList = sessionStorage.getItem(USER_PROFILE_ID_SESSION_ATTRIBUTE);

  useEffect(() => {
    modules.forEach((modulesMap, i) => {
      structureNew[i] = structure.filter(
        (structureFiltered) => structureFiltered.label == modulesMap
      );
    });
    console.log("06262020 useEffect structureNew ", structureNew)
  }, []);

  // useLayoutEffect(() => {
  //   console.log("06252020 useEffect profileDetails ", profileDetails);
  //   const modules = profileDetails.map((module) => module.module);
  //   // const actions = profileDetails
  //   //   .map((item) => item.actions.map((action) => action.action))
  //   //   .flat();
  //   setProfileModules(profileModules.concat(modules));
  //   // setProfileActions(profileActions.concat(actions));
  // }, [profileDetails]);

  // useLayoutEffect(() => {
  //   console.log("06252020 useEffect profileModules ", profileModules);
  //   structureNew = structure.filter(
  //     (structureFiltered) => structureFiltered.label == "Inward"
  //   );
  //   console.log("06252020 structureNew ", structureNew);
  // }, [profileModules]);

  // // // should be in UserContext for global use
  // const retrieveProfileDetails = useCallback(() => {
  //   const profileListArr = profileList.split(",");
  //   profileListArr.forEach((profileListArrMap) => {
  //     ProfileMaintenanceService.retrieveProfileDetails(profileListArrMap).then(
  //       // dapat makuha din menu?
  //       (response) => {
  //         console.log(
  //           "06252020 retrieveProfileDetails response.data ",
  //           response.data
  //         );
  //         setProfileDetails(response.data);
  //       }
  //     );
  //   });
  // });

  var structure = [
    { id: 0, label: "Dashboard", link: "/test/dashboard", icon: <HomeIcon /> },
    {
      id: 1,
      label: "Test1",
      link: "/test1",
      icon: <InboxIcon />,
    },
    {
      id: 2,
      label: "Test2",
      link: "/test2",
      icon: <PresentToAllIcon />,
    },
    { id: 3, type: "divider" },
    {
      id: 4,
      label: "Test3",
      link: "/test3",
      icon: <ListAltIcon />,
      children: [
        {
          label: "Test4",
          link: "/test4",
          icon: <LanguageIcon />,
        },
        {
          label: "Test5",
          link: "/test5",
          icon: <ListIcon />,
        },
      ],
    },
    {
      id: 5,
      label: "Test6",
      link: "/test6",
      icon: <DescriptionIcon />,
    },
    {
      id: 6,
      label: "Test7",
      link: "/test7",
      icon: <AccountBalanceWallet />,
      children: [
        {
          label: "Test8",
          link: "/test8",
          icon: <FaceIcon />,
        },
        {
          label: "Test9",
          link: "/test9",
          icon: <TransferWithinAStationIcon />,
        },
        {
          label: "Test10",
          link: "/test10",
          icon: (
            <Avatar alt="Pesonet" src={pesonetlogo} className={classes.small} />
          ),
        },
        {
          label: "Test11",
          link: "/test11",
          icon: <PeopleAlt />,
        },
      ],
    },
    {
      id: 7,
      label: "Test12",
      link: "/test12",
      icon: <EditIcon />,
    },
  ];

  useEffect(function() {
    window.addEventListener("resize", handleWindowWidthChange);
    handleWindowWidthChange();
    return function cleanup() {
      window.removeEventListener("resize", handleWindowWidthChange);
    };
  });

  return (
    <Drawer
      variant={isPermanent ? "permanent" : "temporary"}
      className={classNames(classes.drawer, {
        [classes.drawerOpen]: isSidebarOpened,
        [classes.drawerClose]: !isSidebarOpened,
      })}
      classes={{
        paper: classNames({
          [classes.drawerOpen]: isSidebarOpened,
          [classes.drawerClose]: !isSidebarOpened,
        }),
      }}
      open={isSidebarOpened}
    >
      <div className={classes.toolbar} />
      <div className={classes.mobileBackButton}>
        <IconButton onClick={() => toggleSidebar(layoutDispatch)}>
          <ArrowBackIcon
            classes={{
              root: classNames(classes.headerIcon, classes.headerIconCollapse),
            }}
          />
        </IconButton>
      </div>
      <List className={classes.sidebarList}>
        {structureNew.map((link) => (
          <SidebarLink
            key={link.id}
            location={location}
            isSidebarOpened={isSidebarOpened}
            {...link}
          />
        ))}
      </List>
    </Drawer>
  );

  function handleWindowWidthChange() {
    var windowWidth = window.innerWidth;
    var breakpointWidth = theme.breakpoints.values.md;
    var isSmallScreen = windowWidth < breakpointWidth;

    if (isSmallScreen && isPermanent) {
      setPermanent(false);
    } else if (!isSmallScreen && !isPermanent) {
      setPermanent(true);
    }
  }
}

export default withRouter(Sidebar);

如您所见, structureNew包含在一些数组操作后在useEffect中形成的菜单和子菜单

但是,我的问题是页面首先呈现并调用structureNew 此时, structureNew为空

我想在渲染页面之前先形成structureNew

有什么办法可以使用钩子来做到这一点?

TIA

为什么不创建一个structureNew新作为 State 并在那个 useEffect 中设置结构新?

我建议添加一个加载器,例如:

const [loading, setLoading] = useState(true)

然后在进行操作后将加载设置为 false:

setLoading(false)

在您添加回报之前:

if(loading){
    return(<LoaderComponent/>)
}
return(
//your main return
)

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM