【问题标题】:Opening Drawer from different file (Material-UI, React)从不同文件打开抽屉(Material-UI,React)
【发布时间】:2020-02-28 14:42:38
【问题描述】:

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


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


所以我认为我需要在 Dashboard 文件中直接拥有drawerOpen 状态和函数,但是如何在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>
  );
};

【问题讨论】:

  • 请添加一些代码。抽屉触发器,或者组件什么的。
  • 我添加了很多代码,我制作了最小的可理解版本,希望它有意义

标签: reactjs material-ui


【解决方案1】:

您将需要将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>
}

编辑: &lt;Route&gt; 不应传递内联组件(除非保存路由的组件从不更新。您实际上应该只传递不需要任何道具的组件。设置@987654324 @ 到内联的功能组件,这将导致渲染组件的实例在包含重新渲染的路由时被销毁并重新安装(功能组件功能被重新定义)。我认为这就是你的动画的原因很可能无法正常工作。

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

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>
}

【讨论】:

  • 我认为这就是我已经在做的事情,我用大量代码编辑了这个问题,看起来我们也在做同样的事情,但这会导致抽屉没有任何动画。这就是为什么我认为我必须将“控制器”部分移动到dashboard.js
  • 好的,我认为您的代码中可能存在一个非常微妙的错误。您希望避免将内联组件传入 Route,因为每次 App 重新渲染时,组件都会重新定义,导致实例被销毁然后重新安装。您可能需要进行相当大的更改才能解决此问题。我会用一些可能的解决方案更新我的回复...
  • 是的,我知道这不是最好的方法,但我不知道如何以任何其他方式在路线中传递道具(任何帮助制作清洁器的人也将不胜感激)但会这实际上与动画不显示有什么关系?
  • 非常感谢您指出问题,我已经在使用 redux,所以我只是将所有功能转移到 redux,现在它的工作完美!
猜你喜欢
  • 2020-10-27
  • 2020-07-07
  • 2021-11-01
  • 1970-01-01
  • 2018-09-28
  • 1970-01-01
  • 2018-03-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多