ReactJS Hook-如何重新渲染其他组件

时间:2020-09-09 07:36:19

标签: reactjs typescript react-hooks

我在这里有三个组成部分。 MainComponent包括其他两个。我想做的是,更改WebHeaderComponent中的select输入将刷新sidemenucomponent布局。但是当我尝试这样做时提示错误。

MainComponent
  -> WebHeaderComponent
  -> SideMenuComponent

MainComponent.tsx

const { Content } = Layout;

const MainComopnent: FunctionComponent = () => {
  const [collapsed, setCollapsed] = useState(false);
  const [menuList, setMenuList] = useState([]);
  const services = useContext(ServicesContext);
  const { MenuService } = services;
  const { AuthenticationService } = services;

  useEffect(() => {
    const requestOption = {
      method: "post",
      body: JSON.stringify({
        userCode: AuthenticationService.getUserModel().userCode, 
        roleId: AuthenticationService.getUserModel().roleId
      })
    }

    MenuApi.getSideMenu(requestOption).then((result) => {
      console.log(result);
      const temp = MenuService.groupMenu(result);
      setMenuList(temp);
    });
  }, []);
  const value = { collapsed, setCollapsed };
  
  return (
    <SideMenuCollapsedContext.Provider value={value}>
      <Layout className="layout">
        <SideMenuComponent menuList={MenuService.getGroupMenu()}></SideMenuComponent>
        <Layout className="site-layout">
          <WebHeaderComponent></WebHeaderComponent>
          <Content
            className="site-layout-background"
            style={{
              margin: "24px 16px",
              padding: 24,
              minHeight: 280,
              overflowY: "scroll",
            }}
          >
            <AppRoutes />
          </Content>
        </Layout>
      </Layout>
    </SideMenuCollapsedContext.Provider>
  );
};
export default MainComopnent;

WebHeaderComponent.tsx

const { Header } = Layout;

const WebHeaderComponent  = () => {
  const services = useContext(ServicesContext);
  const { MenuService } = services;
  const { AuthenticationService } = services;
  const { UserInfoService } = services;
  const [userRoleList, setUserRoleList] =  useState<Array<any>>([]);
  const {collapsed, setCollapsed} = useContext(SideMenuCollapsedContext);

  const toggle = () => {
    setCollapsed(!collapsed);
  };

  useEffect(() => {
    const data = { userId: AuthenticationService.getUserModel().userId};
    SysUserApi.searchSysUserRole(data).then((res) => {
      setUserRoleList(res)
    })
  },[]);  

  const handleRoleChange = (selectedRoleId) => {
    console.log('before: ' + selectedRoleId);
    AuthenticationService.setRoleId(selectedRoleId);
    console.log('after: ' + AuthenticationService.getUserModel().roleId)
  }

  return (
    <Header className="site-layout-background" style={{ padding: 0 }}>
      {React.createElement(
        collapsed ? MenuUnfoldOutlined : MenuFoldOutlined,
        {
          className: "trigger",
          style: { paddingLeft: "10px", fontSize: "20px" },
          onClick: toggle,
        }
      )}

      <div
        style={{
          float: "right",
          paddingRight: "20px",
          display: "flex",
          alignItems: "center",
        }}
      >
          <div><span>用戶:{AuthenticationService.getUserModel().userName}</span></div>
          <div style={{ paddingLeft: "10px" }}>
            <span>公司-角色:</span>
            <Select 
              style={{ width: 120 }} 
              defaultValue={AuthenticationService.getUserModel().roleId}
              onChange={handleRoleChange}
            >
              {userRoleList.map(item => (
                <option
                  key={item.roleId}
                  value={item.roleId}
                >
                  {item.roleName}
                </option>
              ))}
            </Select>
          </div>
        <div style={{ paddingLeft: "10px" }}>
          <Button type="primary"> Sign Out </Button>
        </div>
      </div>
    </Header>
  );
}

export default WebHeaderComponent;

SideMenuComponent.tsx

const { Sider } = Layout;
const { SubMenu } = Menu;

const createSubMenus = (menuList): any => {
  const menus: any = [];
  for (const subMenuItem of menuList) {
    if (subMenuItem.children && subMenuItem.children.length > 0) {
      menus.push(
        <SubMenu
          key={subMenuItem.funcId}
          title={
            <span>
              <MailOutlined />
              <span className="fontWt">{subMenuItem.funcName}</span>
            </span>
          }
        >
          {createSubMenus(subMenuItem.children)}
        </SubMenu>
      );
    } else {
      menus.push(
        <Menu.Item key={subMenuItem.funcId + subMenuItem.parentId}>
          {subMenuItem.funcName}
          <Link to={"/app" + subMenuItem.funcUrl} replace></Link>
        </Menu.Item>
      );
    }
  }
  return menus;
};

const SideMenuComponent = ({ menuList }) => {
  const value = useContext(SideMenuCollapsedContext);
  const [subMenuList, setSubMenuList] = useState([]);
  const { collapsed, setCollapsed } = value;

  useEffect(() => {
    setSubMenuList(createSubMenus(menuList));
  }, [menuList]);

  const handleCollapsed = (collapsed) => {
    setCollapsed(collapsed);
  };

  return (
    <Sider collapsible collapsed={collapsed} onCollapse={handleCollapsed}>
      <div className="logo" />
      <Menu theme="dark" mode="inline" defaultSelectedKeys={["1"]}>
        {/* <Menu.Item key="1" icon={<UserOutlined />}>
          <Link to="/app/producttomms">Share Product to MMS</Link>
        </Menu.Item>
        <Menu.Item key="2" icon={<UserOutlined />}>
          <Link to="/app/paymentorderanalyzer">Payment Order Analyzer</Link>
        </Menu.Item>
        <Menu.Item key="3" icon={<UserOutlined />}>
          <Link to="/app/masterdatainitializer">Master Data Initializer</Link>
        </Menu.Item> */}
        {subMenuList}
      </Menu>
    </Sider>
  );
};

export default SideMenuComponent;

在WebHeaderComponent中,下面有一个选择输入。我要做的是,一旦我从选择输入中更改了值,就在上下文中更新了一个值,我希望sideMenuComponent会被来自上下文的新菜单列表刷新。

但是,会提示错误消息。

Can't perform a React state update on an unmounted component. This is a no-op, but it indicates a memory leak in your application.

1 个答案:

答案 0 :(得分:0)

提升状态

  • 将您的状态提升到共同祖先(即父母)。

  • 由于两者都可以访问该状态,因此您可以传递一个孩子的回调以更新父对象。

  • 由于两个孩子共享相同的状态,因此又更新了另一个孩子。

export default function Parent() {
  const [text, setText] = React.useState('not yet updated');

  return (
    <div>
      <Child1 text={text} />
      <Child2 onClick={setText} />
    </div>
  );
}

function Child1({ text }) {
  return <p>{text}</p>
}

function Child2({ onClick }) {
  return <button onClick={() => onClick('Child2 updated the state')}>Update</button>
}