We showed in Basics how we can factor Views into functions. It's best practice to have a main View function for each HyperView. Create views as pure functions of input data and state:
inputs -> View viewId ()
We can write multiple view functions with our HyperView as the context, and factor them however is most convenient:
messageButton :: Text -> View Message ()
messageButton msg = do
button (SetMessage msg) ~ btn $ text $ "Say " <> msg
Generic View functions can be used in any context:
header :: Text -> View ctx ()
header txt = do
el ~ bold $ text txt
Now that we have created multiple smaller view functions, we can refactor our main View function to use them and avoid repeating ourselves
messageView :: Text -> View Message ()
messageView m = do
header m
messageButton "Salutations!"
messageButton "Good Morning!"
messageButton "Goodbye"
You may be tempted to use HyperViews to create reusable "Components". This leads to object-oriented designs that don't compose well. We are using a functional language; our main unit of reuse should be functions!
The header view function we defined above has a generic context that can be used in any view. This approach is great for reusing styles or layout. But what if we want to reuse interactivity? We can pass an Action into the view function as a parameter:
styledButton :: (ViewAction (Action id)) => Action id -> Text -> View id ()
styledButton clickAction lbl = do
button clickAction ~ btn $ text lbl
where
btn = pad 10 . bg Primary . hover (bg PrimaryLight) . rounded 5
We can create more complex view functions by passing state in as a parameter. Here's a button that toggles between a checked and unchecked state for any HyperView:
toggleCheckbox :: (ViewAction (Action id)) => (Bool -> Action id) -> Bool -> View id ()
toggleCheckbox setChecked isSelected = do
tag "input" @ att "type" "checkbox" . onClick (setChecked (not isSelected)) . checked isSelected ~ big $ none
where
big = width 32 . height 32
toggler :: Bool -> View Toggler ()
toggler b =
row ~ gap 10 $ do
toggleCheckbox Toggle b
text "I am using view functions"
Don't use HyperViews to keep your code DRY. Instead, think about which subsections of a page ought to update independently. Those are HyperViews. If you need reusable interactivity, use view functions whenever possible.