Combinator library for writing React vDOM
It it is heavily inspired by purescript-smolder.
The top level module exports
renderIn
:: (Array ReactElement -> ReactElement)
-> SpaceM
-> ReactElement
render
:: SpaceM
-> Array ReactElement
which you can chain with render
method of your spec:
s :: ReactSpec Unit Unit
s = spec unit (map (renderIn React.DOM.div') <<< render)
where
render :: ReactThis Unit Unit -> SpaceM
render this = pure $
div !. "greeting" $ do
text "Hello World!
Run
npm run example:build
npm run example:serve
It will compile the following simple example:
greeting
:: forall eff
. ReactClass
(Greeting
( props :: ReactProps
, refs :: ReactRefs ReadOnly
, state :: ReactState ReadWrite
| eff))
greeting = createClassStateless'
\(Greeting { name, onChange }) chldrn
-> renderIn React.DOM.div' do
div !. "greeting" $ do
label do
div do
h1 do
elements chldrn
text " "
text name
text if not (S.null name) then "!" else ""
-- note that you don't need to pass `empty` to `input`
input ! P.value name ! P.onChange (handleChange onChange)
where
handleChange onChange ev = do
v <- pure (unsafeCoerce ev).target.value
onChange v
newtype Counter eff = Counter
{ counter :: Int
, onClick :: Eff eff Unit
}
counter
:: forall eff
. ReactClass
(Counter
( props :: ReactProps
, refs :: ReactRefs ReadOnly
, state :: ReactState ReadWrite
| eff))
counter = createClassStateless'
(\(Counter { counter: c, onClick: onClick' }) chldrn
-> renderIn React.DOM.div' do
div do
elements chldrn
span $ text (show c)
button ! onClick (handleClick onClick') $ do
text "count")
where
handleClick onClick ev = onClick
base :: ReactClass Unit
base = createClass (spc { displayName = "BaseClass" })
where
spc = spec { name: "John", counter: 0 }
(map (renderIn React.DOM.div') <<< renderFn)
handleName this name = do
transformState this (_ { name = name })
handleCounter this = do
transformState this (\st@{counter} -> st { counter = (counter + 1) })
renderFn this = do
{ counter, name } <- readState this
pure $ do
greeting ^^ (Greeting { name, onChange: handleName this })
$ do
span $ text "Hello"
counter ^^ (Counter { counter, onClick: handleCounter this })
$ do
h1 $ "Count on the sea..."
Often in React
you want to render a node which is present under some
condition. You might have a Maybe String
in your props that you'd like to
show only if you have a Just
value. Since SpaceM
is an instance of
Foldable
type class you can do that in this way:
nCls :: ReactClass { name :: String }
nCls = createClassStateless \{ name } -> renderIn React.DOM.div' do
h1 !. "title" $ do
text "Hello "
span !. "name" $ text name
mSpec :: forall eff. ReactSpec { mName :: Maybe String } Unit eff
mSpec = spec unit renderFn
where
renderFn this = do
{ mName } <- getProps this
let mNameNode = (nCls ^ _) <$> mName
pure $ renderIn React.DOM.div' $ do
h1 !. "app" $ do
text "Hello App"
sequence_ mNameNode
Checkout examples for a echoApp
component.
For another example you can check out purescript-isomorphic-react-example.
Another common pattern is to conditionally include part of a ui. You can use when
for that:
renderIn React.DOM.div' $ do
h1 $ title "Hello"
when condition do
-- note that `React.Space.DOM.input` elements do not accept children (unlike `React.DOM.input`)
input ! P.onChange (handleChange this)