Hyperstack 和 MaterialUI 抽屉切换状态导致抽屉反复打开和关闭
Hyperstack and MaterialUI Drawer Toggling State is causing the drawer to open and close repeatedly
我正在 Hyperstack 项目中使用 MaterialUI 实现标题栏和菜单抽屉。我有两个组件,一个 Header
组件和一个 Menu
组件。 Menu
组件是可扩展的 Drawer
。我将状态存储在 Header
组件中,并将它和一个处理程序传递给 Menu
组件,以便在单击抽屉关闭按钮时切换抽屉状态。出于某种原因,抽屉只是非常快速和反复地切换打开和关闭。
在我实现关闭按钮之前,抽屉打开得很好。我已经尝试将状态向上移动到主应用程序组件并将其一直向下传递,但它产生相同的结果。我尝试在 Header
组件上设置一个 class 函数,并从 Menu
组件中调用它,而不是传入事件处理程序。
Header
组件
class Header < HyperComponent
before_mount do
@drawer_open = false
end
def toggle_drawer
mutate @drawer_open = !@drawer_open
end
render(DIV) do
AppBar(position: 'static', class: 'appBar') do
Toolbar do
IconButton(class: 'menuButton', color: 'inherit', aria_label: 'Menu') do
MenuIcon(class: 'icon')
end
.on(:click) do
toggle_drawer
end
Typography(variant: 'h6', color: 'inherit', class: 'grow') { 'Admin Main' }
Button(color: 'inherit', class: 'float-right') { 'Login' } # unless App.history != '/admin'
end
end
Menu(open_drawer: @drawer_open, toggle_drawer: toggle_drawer)
end
end
Menu
组件
class Menu < HyperComponent
param :open_drawer
param :toggle_drawer
def menu_items
%w(Main Inventory Customers)
end
def is_open?
@OpenDrawer
end
render(DIV) do
Drawer(className: 'drawer, drawerPaper', variant: 'persistent', anchor: 'left', open: is_open?) do
IconButton(className: 'drawerHeader') { ChevronLeftIcon() }
.on(:click) { @ToggleDrawer }
List do
menu_items.each do |mi|
ListItem(button: true, key: mi) { ListItemText(primary: mi) }
end
end
end
end
end
我希望抽屉在单击打开按钮时打开并在单击关闭按钮时关闭,但它打开和关闭的速度非常快。
它快速打开和关闭的原因是您将 toggle_drawer
的 值 从 Header
组件传递给 Menu
零件。每次调用 toggle_drawer
时,它都会更改状态变量 @drawer_open,并重新渲染组件,然后重复泡沫-漂洗-重复。
你需要做的是将 proc
传递给 Menu,然后让 Menu
调用 on_click
处理程序中的过程。
所以它看起来像这样:
class Header < HyperComponent
...
render(DIV) do
...
Menu(open_drawer: @drawer_open, toggle_drawer: method(:toggle_drawer))
end
end
和
class Menu < HyperComponent
...
param :toggle_drawer
...
IconButton(className: 'drawerHeader') { ChevronLeftIcon() }
.on(:click) { @ToggleDrawer.call } # note you have to say .call
...
end
By the way nice article here on how method(:toggle_drawer)
works
and compares it the same behavior in Javascript.
但是等等! Hyperstack 有一些很好的语法糖,使它更具可读性。
不应将 toggle_drawer
声明为普通参数,而应使用 fires
方法声明它,表明您将向调用组件触发事件(或回调)。这不仅会让你的生活更轻松一些,而且还会向 reader 宣布你的意图。
class Menu < HyperComponent
...
fires :toggle_drawer # toggle_drawer is a callback/event that we will fire!
...
IconButton(className: 'drawerHeader') { ChevronLeftIcon() }
.on(:click) { toggle_drawer! } # fire the toggle_drawer event (note the !)
...
end
现在Header
可以使用正常的事件处理程序语法:
class Header < HyperComponent
...
render(DIV) do
...
Menu(open_drawer: @drawer_open)
.on(:toggle_drawer) { toggle_drawer }
end
end
顺便说一句,如果我能提供一点风格建议:因为菜单只能关闭抽屉,这就是我所说的事件,在事件处理程序中我会直接改变抽屉状态(并且只是失去toggle_drawer 方法)。
这样看代码就很清楚你要过渡到什么状态了
生成的代码如下所示:
class Header < HyperComponent
before_mount do
@drawer_open = false # fyi you don't need this, but its also not bad practice
end
render(DIV) do
AppBar(position: 'static', class: 'appBar') do
Toolbar do
IconButton(class: 'menuButton', color: 'inherit', aria_label: 'Menu') do
MenuIcon(class: 'icon')
end.on(:click) { mutate @drawer_open = true }
Typography(variant: 'h6', color: 'inherit', class: 'grow') { 'Admin Main' }
Button(color: 'inherit', class: 'float-right') { 'Login' } # unless App.history != '/admin'
end
end
Menu(open_drawer: @drawer_open)
.on(:close_drawer) { mutate @drawer_open = false }
end
end
我正在 Hyperstack 项目中使用 MaterialUI 实现标题栏和菜单抽屉。我有两个组件,一个 Header
组件和一个 Menu
组件。 Menu
组件是可扩展的 Drawer
。我将状态存储在 Header
组件中,并将它和一个处理程序传递给 Menu
组件,以便在单击抽屉关闭按钮时切换抽屉状态。出于某种原因,抽屉只是非常快速和反复地切换打开和关闭。
在我实现关闭按钮之前,抽屉打开得很好。我已经尝试将状态向上移动到主应用程序组件并将其一直向下传递,但它产生相同的结果。我尝试在 Header
组件上设置一个 class 函数,并从 Menu
组件中调用它,而不是传入事件处理程序。
Header
组件
class Header < HyperComponent
before_mount do
@drawer_open = false
end
def toggle_drawer
mutate @drawer_open = !@drawer_open
end
render(DIV) do
AppBar(position: 'static', class: 'appBar') do
Toolbar do
IconButton(class: 'menuButton', color: 'inherit', aria_label: 'Menu') do
MenuIcon(class: 'icon')
end
.on(:click) do
toggle_drawer
end
Typography(variant: 'h6', color: 'inherit', class: 'grow') { 'Admin Main' }
Button(color: 'inherit', class: 'float-right') { 'Login' } # unless App.history != '/admin'
end
end
Menu(open_drawer: @drawer_open, toggle_drawer: toggle_drawer)
end
end
Menu
组件
class Menu < HyperComponent
param :open_drawer
param :toggle_drawer
def menu_items
%w(Main Inventory Customers)
end
def is_open?
@OpenDrawer
end
render(DIV) do
Drawer(className: 'drawer, drawerPaper', variant: 'persistent', anchor: 'left', open: is_open?) do
IconButton(className: 'drawerHeader') { ChevronLeftIcon() }
.on(:click) { @ToggleDrawer }
List do
menu_items.each do |mi|
ListItem(button: true, key: mi) { ListItemText(primary: mi) }
end
end
end
end
end
我希望抽屉在单击打开按钮时打开并在单击关闭按钮时关闭,但它打开和关闭的速度非常快。
它快速打开和关闭的原因是您将 toggle_drawer
的 值 从 Header
组件传递给 Menu
零件。每次调用 toggle_drawer
时,它都会更改状态变量 @drawer_open,并重新渲染组件,然后重复泡沫-漂洗-重复。
你需要做的是将 proc
传递给 Menu,然后让 Menu
调用 on_click
处理程序中的过程。
所以它看起来像这样:
class Header < HyperComponent
...
render(DIV) do
...
Menu(open_drawer: @drawer_open, toggle_drawer: method(:toggle_drawer))
end
end
和
class Menu < HyperComponent
...
param :toggle_drawer
...
IconButton(className: 'drawerHeader') { ChevronLeftIcon() }
.on(:click) { @ToggleDrawer.call } # note you have to say .call
...
end
By the way nice article here on how
method(:toggle_drawer)
works and compares it the same behavior in Javascript.
但是等等! Hyperstack 有一些很好的语法糖,使它更具可读性。
不应将 toggle_drawer
声明为普通参数,而应使用 fires
方法声明它,表明您将向调用组件触发事件(或回调)。这不仅会让你的生活更轻松一些,而且还会向 reader 宣布你的意图。
class Menu < HyperComponent
...
fires :toggle_drawer # toggle_drawer is a callback/event that we will fire!
...
IconButton(className: 'drawerHeader') { ChevronLeftIcon() }
.on(:click) { toggle_drawer! } # fire the toggle_drawer event (note the !)
...
end
现在Header
可以使用正常的事件处理程序语法:
class Header < HyperComponent
...
render(DIV) do
...
Menu(open_drawer: @drawer_open)
.on(:toggle_drawer) { toggle_drawer }
end
end
顺便说一句,如果我能提供一点风格建议:因为菜单只能关闭抽屉,这就是我所说的事件,在事件处理程序中我会直接改变抽屉状态(并且只是失去toggle_drawer 方法)。
这样看代码就很清楚你要过渡到什么状态了
生成的代码如下所示:
class Header < HyperComponent
before_mount do
@drawer_open = false # fyi you don't need this, but its also not bad practice
end
render(DIV) do
AppBar(position: 'static', class: 'appBar') do
Toolbar do
IconButton(class: 'menuButton', color: 'inherit', aria_label: 'Menu') do
MenuIcon(class: 'icon')
end.on(:click) { mutate @drawer_open = true }
Typography(variant: 'h6', color: 'inherit', class: 'grow') { 'Admin Main' }
Button(color: 'inherit', class: 'float-right') { 'Login' } # unless App.history != '/admin'
end
end
Menu(open_drawer: @drawer_open)
.on(:close_drawer) { mutate @drawer_open = false }
end
end