We can add as many HyperViews to a Page as we want. Each will update independently. These can be copies of the same HyperView with unique ViewId values, or completely different HyperView instances
Let's add a Counter and two Message HyperViews to the same page
page :: Page es [Message, Counter]
page = do
pure $ do
hyper Message1 $ messageView "Hello"
hyper Message2 $ messageView "World"
hyper Counter $ viewCount 0
ViewId values must be unique. So if we want more than one of the same HyperView on the same Page, we need a way to differentiate them. In the example above we used two distinct constructors for Message, but we could also use a product type:
data Item = Item UniqueId
deriving (Generic, ViewId)
This is especially useful if we put identifying information in our ViewId, such as a database id. When we embed an item using hyper, we use a unique ViewId generated from that id
page :: Page es '[Item]
page = do
itemIds <- loadDummyItemIds
pure $ do
row ~ gap 4 $ do
forM_ itemIds $ \uid -> do
hyper (Item uid) itemUnloaded
The viewId function can then give us access to said identifier in update or a View
instance HyperView Item es where
data Action Item = Load
deriving (Generic, ViewAction)
update Load = do
Item uid <- viewId
item <- loadDummyItem uid
pure $ itemLoaded item
itemUnloaded :: View Item ()
itemUnloaded = do
Item uid <- viewId
button Load ~ btn $ text $ "Load " <> pack (show uid)
The ViewId is constant for the lifetime of the HyperView, so it won't work to try to cram state into it. Instead, use one of the approaches outlined in Managing State
We can nest smaller, more specific HyperViews inside of a larger parent. You might need this technique to display a list of items which also need to update themselves individually
To illustrate, let's enhance the previous example by creating a parent HyperView for the list of items, with an Action that can reset them
data ItemList = ItemList
deriving (Generic, ViewId)
page :: Page es '[ItemList, Item]
page = do
itemIds <- loadDummyItemIds
pure $ hyper ItemList $ itemList itemIds
And embed the individual Item HyperViews into the Item View
itemList :: [Int] -> View ItemList ()
itemList itemIds = do
row ~ gap 4 . color White $ do
forM_ itemIds $ \itemId -> do
hyper (Item itemId) itemUnloaded
button Reset ~ btnLight $ "Reset"
Add any nested HyperViews to Require to make sure they are handled. The compiler will let you know if you forget
instance HyperView ItemList es where
data Action ItemList = Reset
deriving (Generic, ViewAction)
type Require ItemList = '[Item]
update Reset = do
itemIds <- loadDummyItemIds
pure $ itemList itemIds
Sometimes nesting isn't enough, and we need to directly communicate to other HyperViews. Below, we have an independent HyperView which displays a message, and two ways to control it:
instance HyperView Controls es where
type Require Controls = '[Targeted]
data Action Controls = TriggerMessage
deriving (Generic, ViewAction)
update TriggerMessage = do
trigger Targeted $ SetMessage "Triggered!"
pure controlView