运行应用程序
在本指南的过程中,我们已经多次看到运行Halogen
应用程序的标准方法。在本章中,我们将了解运行Halogen
应用程序时实际发生的情况以及如何从外部控制正在运行的应用程序。
使用runUI和awaitBody
PureScript
应用程序使用它们Main
模块中的main
函数作为它们的入口点。这是Halogen
应用程序的标准main
函数:
module Main where
import Prelude
import Effect (Effect)
import Halogen.Aff as HA
import Halogen.VDom.Driver (runUI)
main :: Effect Unit
main = HA.runHalogenAff do
body <- HA.awaitBody
runUI component unit body
-- 假设您已经为您的应用程序定义了一个根组件
component :: forall query input output m. H.Component query input output m
component = ...
main
中使用的最重要的函数是runUI
函数。为runUI
提供根组件、根组件的input
值和对DOM
元素的引用,它将向Halogen
虚拟DOM
提供您的应用程序. 然后,虚拟DOM
将在该元素上渲染您的应用程序,并在应用程序运行期间保持它。
runUI
:: forall query input output
. Component query input output Aff
-> input
-> DOM.HTMLElement
-> Aff (HalogenIO query output Aff)
如您所见,runUI
函数要求您的Halogen
应用程序最终可以在Aff monad
中运行。在本指南中,我们使用了诸如monadefect
和MonadAff
之类的约束,这些约束是Aff
所满足的,所以我们很清楚。
如果您选择为您的应用程序使用另一个
monad
,那么您需要在将您的应用程序提供给runUI
之前将其提升以在Aff
中运行。Real World Halogen使用一个自定义的AppM monad
,这是一个很好的例子。
除了runUI
,我们还使用了另外两个辅助函数。首先,我们使用awaitBody
等待页面加载,然后获取对<body>
标签的引用作为应用程序控制的根HTML
元素。其次,我们使用runHalogenAff
从Effect
内部启动异步effects
(我们的Aff
代码包含awaitBody
和runUI
).这是必要的,因为awaitBody
、runUI
和我们的应用程序运行在Aff monad
中,而PureScript
的main
函数必须在Effect
中。
我们在这里使用的main
函数是运行Halogen
应用程序的标准方式,它是页面上唯一运行的东西。但是,有时您可能会使用Halogen
来接管页面的一部分,或者您可能正在运行多个Halogen
应用程序。在这些情况下,您可能会用到一对不同的辅助函数:
awaitLoad
阻塞,直到文档加载完毕,以便您可以安全地检索对页面上HTML
元素的引用selectElement
可用于定位页面上的特定元素以将应用程序嵌入其中
使用HalogenIO
当您使用runUI
运行Halogen
应用程序时,您会收到HalogenIO
类型的函数记录. 这些函数可用于从应用程序外部控制您的根组件。从概念上讲,它们就像您的应用程序的临时父组件。
type HalogenIO query output m =
{ query :: forall a. query a -> m (Maybe a)
, messages :: Event output
, dispose :: m Unit
}
query
函数类似于支持tell
和request
的H.query
函数。这允许您从应用程序外部向应用程序的根组件发送query
.messages
事件可用于订阅来自组件的output
消息流 —— 它就像我们提供给slot
函数的处理程序,除了在这里我们可以执行一些effect
而不是评估一个action
。dispose
函数可用于停止和清理Halogen
应用程序。这将杀死所有分叉的线程,关闭所有订阅,等等。
您不能在应用程序的根目录中使用tell
和request
,但是可以使用mkTell
和mkRequest
函数(如下例所示)来达到类似的效果。
Halogen
应用中一个常见的模式是使用一个Route
组件作为应用的根,当URL
改变时使用HalogenIO
中的query
函数来触发应用中的路由改变.您可以在Real World HalogenMain.purs
文件中看到执行此操作的完整示例。
完整示例: 使用HalogenIO控制按钮
您可以将此示例粘贴到Try PureScript中,以探索使用HalogenIO
来控制应用程序的根组件。
module Example.Driver.IO.Main where
import Prelude
import Data.Maybe (Maybe(..))
import Effect (Effect)
import Effect.Console (log)
import Halogen (liftEffect)
import Halogen as H
import Halogen.HTML as HH
import Halogen.Aff as HA
import Halogen.HTML.Events as HE
import Halogen.HTML.Properties as HP
import Halogen.Subscription as HS
import Halogen.VDom.Driver (runUI)
main :: Effect Unit
main = HA.runHalogenAff do
body <- HA.awaitBody
io <- runUI component unit body
_ <- liftEffect $ HS.subscribe io.messages \(Toggled newState) -> do
liftEffect $ log $ "Button was internally toggled to: " <> show newState
pure Nothing
state0 <- io.query $ H.mkRequest IsOn
liftEffect $ log $ "The button state is currently: " <> show state0
void $ io.query $ H.mkTell (SetState true)
state1 <- io.query $ H.mkRequest IsOn
liftEffect $ log $ "The button state is now: " <> show state1
-- Child component implementation
type Slot = H.Slot Query Message
data Query a
= IsOn (Boolean -> a)
| SetState Boolean a
data Message = Toggled Boolean
data Action = Toggle
type State = { enabled :: Boolean }
component :: forall i m. H.Component Query i Message m
component =
H.mkComponent
{ initialState
, render
, eval: H.mkEval $ H.defaultEval
{ handleAction = handleAction
, handleQuery = handleQuery
}
}
initialState :: forall i. i -> State
initialState _ = { enabled: false }
render :: forall m. State -> H.ComponentHTML Action () m
render state =
let
label = if state.enabled then "On" else "Off"
in
HH.button
[ HP.title label
, HE.onClick \_ -> Toggle
]
[ HH.text label ]
handleAction :: forall m. Action -> H.HalogenM State Action () Message m Unit
handleAction = case _ of
Toggle -> do
newState <- H.modify \st -> st { enabled = not st.enabled }
H.raise (Toggled newState.enabled)
handleQuery :: forall m a. Query a -> H.HalogenM State Action () Message m (Maybe a)
handleQuery = case _ of
IsOn k -> do
enabled <- H.gets _.enabled
pure (Just (k enabled))
SetState enabled a -> do
H.modify_ (_ { enabled = enabled })
pure (Just a)
下一步
本指南展示了Halogen
应用的基本构建块。我们了解了Halogen
如何提供一种类型安全、声明式的方式来使用称为组件的可重用部分构建复杂的应用程序.我们学习了如何编写生Halogen HTML
的函数、如何编写单个组件以及如何在其他组件中渲染组件。我们还学习了组件如何相互通信以及如何运行完整的Halogen
应用程序。
您现在知道Halogen
是如何工作的,但您可能还不太习惯使用该库构建一个真正的应用程序。这是完全正常的!有更多资源可帮助您继续了解Halogen
。
- 要更深入地了解您在本指南中学到的概念,请浏览概念参考。
- 要以慢节奏、自下而上的方式学习
Halogen
,请尝试查看Jordan Martinez
的Learn Halogen存储库。 - 要了解如何在
Halogen
中构建真实世界的应用程序,请查看Real World Halogen手册和示例应用程序。