Core concepts
Props
Inspired by React props, miso allows a parent component to pass read-only data down to a child via props. Props are synchronous: when they change in the parent, the child re-renders.
Props vs component-local state
- model — component-local state, owned and mutated exclusively by the component through its
update. No other component can write to it directly. - props — data inherited from the parent. Props flow downward and are read-only from the child's perspective; the parent decides what to pass at mount time.
This mirrors React's distinction between useState and the props a function component receives.
When to use props
Props suit metadata — contextual or configuration data the child needs to know about but should not own: a display name, a theme token, a locale, a read-only identifier. If the data drives the child's own business logic — counters it increments, form fields it edits, async state it manages — it belongs in the child's model. Prefer props for "what the child should know" and the model for "what the child should do".
Props in view and update
view always takes props as its second argument; top-level applications have no parent, so props are ():
view :: context -> props -> model -> View context model actionUse getProps inside Effect (or Miso.Lens.view props) to read the current value:
update = \case
SomeAction -> do
p <- getProps
io_ (consoleLog (ms (show p)))Passing props to a child
Use mountWithProps_ (keyed) or mountWithProps (unkeyed) in the parent's view:
mountWithProps_
:: (Eq context, Eq model, Eq props)
=> MisoString -> props
-> Component context props model action
-> View context parentModel parentActionExample: child reading parent-supplied props
-- The props type: what the parent shares with the child
newtype Greeting = Greeting MisoString deriving (Eq)
-- context props model action
child :: Component () Greeting () ChildAction
child = vcomp () updateChild viewChild
where
viewChild :: () -> Greeting -> () -> View () () ChildAction
viewChild _ (Greeting g) _ = H.div_ [] [ text ("Hello, " <> g <> "!") ]
updateChild :: ChildAction -> Effect () Greeting () ChildAction
updateChild = \case
ReadGreeting -> do
Greeting g <- getProps
io_ (consoleLog g)
-- Parent component: owns the greeting, passes it to the child as props
parentComp :: App ParentModel ParentAction
parentComp = vcomp (ParentModel "World") noop viewParent
where
viewParent :: () -> () -> ParentModel -> View () ParentModel ParentAction
viewParent _ _ (ParentModel g) = mountWithProps_ "child" (Greeting g) child
newtype ParentModel = ParentModel MisoString deriving (Eq)
data ChildAction = ReadGreeting
data ParentAction- Props flow from parent to child explicitly via
mountWithProps_; the child's context is the shared global context. getPropsinside the child'supdateyields aGreeting. The child only sees what the parent chose to share.- The root
Appalways hascontext ~ ()andprops ~ (); no plumbing is needed forstartApp. - The
onPropsChangedhook dispatches an action with the previous and current props whenever they change.
Try it
Hello, World!
props changed 0 times
-- The props type: what the parent shares with the child.
newtype Greeting = Greeting MisoString
deriving (Show, Eq)
-- The parent owns the name and passes it down as props.
data NamerAction = NameChanged MisoString
namer :: Eq ctx => Component ctx () MisoString NamerAction
namer = component "World" update view
where
update (NameChanged s) = this .= s
view _ () name =
H.div_ []
[ H.input_ [ HP.value_ name, HE.onInput NameChanged, HP.placeholder_ "Your name" ]
, mountWithProps_ "greeter" (Greeting name) greeter -- keyed, with props
]
-- The child reads its props in view and in update.
data GreeterAction = LogProps | PropsChanged Greeting Greeting
greeter :: Component ctx Greeting Int GreeterAction
greeter = (component 0 update view)
{ onPropsChanged = Just PropsChanged } -- react when the parent changes props
where
update = \case
PropsChanged _old _new -> this += 1
LogProps -> do
Greeting g <- getProps -- props are readable in Effect
io_ (consoleLog ("props are: " <> g))
view _ (Greeting g) changes =
H.div_ []
[ H.p_ [] [ "Hello, ", H.strong_ [] [ text g ], "!" ]
, H.p_ [ HP.class_ "muted" ] [ "props changed ", text (ms changes), " times" ]
, H.button_ [ HE.onClick LogProps ] [ "log props to console" ]
]