从其他文件(材料UI,React)打开抽屉

时间:2020-02-28 14:42:38

标签: reactjs material-ui

我正在尝试从文件“ Navbar”中打开文件“ dashboard”中的抽屉,您可能已经猜到我想从navbar中打开需要在仪表板文件中的抽屉,听起来很容易,但是我可以使它正常工作。我尝试了多种方法,其中一种有效:


在Layout文件中具有切换功能和抽屉打开状态,因此该结构的工作方式如下: navbar.js中的click事件在Layout中运行切换功能->布局中的Toggle函数会更改抽屉打开状态->抽屉打开状态会通过props传递到Dashboard.js中,然后通过props控制抽屉打开状态。使用此方法的唯一缺点是,所有动画均不起作用(缓慢显示抽屉的进出等)


所以我认为我需要直接在Dashboard文件中拥有抽屉打开状态和功能,但是如何获取navbar.js中的按钮以在dashboard.js中运行功能?

我希望我对它的解释足够好,让您理解,任何想法都将不胜感激!如果我需要解释更多内容,请告诉我!

在动画不起作用的情况下编辑1个
Layout.js(当然还有更多的路由等,但是我删除了它们以使文件更整洁):

const Layout = () => {
  const [dashBoardSideNavOpen, setDashBoardSideNavOpen] = React.useState(false);

  const dashBoardSideNavToggle = () => {
    setDashBoardSideNavOpen(!dashBoardSideNavOpen);
  };

  const dashBoardSideNavClose = () => {
    setDashBoardSideNavOpen(false);
  };

  return (
    <Router>
      <NavBar
        dashBoardSideNavToggle={dashBoardSideNavToggle}
      />
      <Switch>
        <Route
          path="/dashboard"
          component={props => (
            <DashBoard
              {...props}
              dashBoardSideNavOpen={dashBoardSideNavOpen}
              dashBoardSideNavToggle={dashBoardSideNavToggle}
              dashBoardSideNavClose={dashBoardSideNavClose}
            />
          )}
        />
      </Switch>
    </Router>

  );
};

export default Layout

Navbar.js:

const NavBar = ({dashBoardSideNavToggle}) => {
  return (
    <Fragment>
      <div className={classes.root}>
        <AppBar className={classes.appBar}>
          <Toolbar>     
            <Box style={{ flexGrow: 1 }}>
              <IconButton color="inherit" onClick={dashBoardSideNavToggle}>
                <MenuIcon />
              </IconButton>
            </Box>
            <Typography variant="h4" style={{ flexGrow: 1 }}>
              <Link component={RouterLink} to="/" color="inherit" underline="none">
                Title
              </Link>
            </Typography>
            <IconButton color="inherit" onClick={userSideNavToggle}>
              <MenuIcon />
            </IconButton>
          </Toolbar>
        </AppBar>
      </div>
      <div className={classes.offset} />
    </Fragment>
  );
};

DashBoard.js:

const DashBoard = ({dashBoardSideNavOpen, dashBoardSideNavToggle, dashBoardSideNavClose}) => {
  return (
    <Router>
      <div className={classes.root}>
        <Drawer
          variant="temporary"
          anchor={'left'}
          open={dashBoardSideNavOpen}
          onOpen={dashBoardSideNavToggle}
          onClose={dashBoardSideNavToggle}
          classes={{
            paper: classes.drawerPaper
          }}
          ModalProps={{
            keepMounted: true
          }}
        >
          {drawerContent}
        </Drawer>
        <Fragment>
          <Switch>
            <Route
              exact
              path={'/dashboard/overview'}
              component={Overview}
            />
          </Switch>
        </Fragment>
      </div>
    </Router>
  );
};

1 个答案:

答案 0 :(得分:3)

您将需要在仪表板和导航栏的公共父组件中保持open状态,然后使该状态和一个用于更新状态的函数传递给需要控制它的任何组件。这是您要寻找的解决方案类型的一个简单的最小示例:

const Parent = () => {
  const [open, setOpen] = useState(false);

  return (
    <div>
      <Controller open={open} onOpenChange={setOpen} />
      <Drawer open={open} />
    </div>
  )
}

const Controler = ({ open, onOpenChange }) => {
  return <button onClick={() => onOpenChange(!open)}>toggle drawer</button>
}

const Drawer = ({ open }) => {
  if (open) return <div>I am open!!</div>
  return <div>I am closed!!</div>
}

编辑: <Route>不应通过内联组件传递(除非该组件包含从不更新的路由。您实际上应该只传递不需要任何道具的组件。) component到一个内联的功能组件,这将导致渲染的组件实例在路由包含重新渲染(功能组件功能得到重新定义)时被破坏并重新安装。为什么您的动画最有可能无法正常工作。

最简单的解决方案可能是创建一个上下文,该上下文可以在树上发送必要的抽屉函数,这样您就无需将它们作为道具传递。像这样:

const DrawerContext = React.createContext({ setOpen: () => {}, open: false });

const Parent = () => {
  const [open, setOpen] = useState(false);

  return (
    <DrawerContext.Provider value={{setOpen}}>
      <div>
        <Controller/>
        <Drawer />
      </div>
    </DrawerContext.Provider
  )
}

const Controler = () => {
  const { open, setOpen } = useContext(DrawerContext);
  return <button onClick={() => onOpenChange(!open)}>toggle drawer</button>
}

const Drawer = () => {
  const { open } = useContext(DrawerContext);

  if (open) return <div>I am open!!</div>
  return <div>I am closed!!</div>
}