Low-level React Bindings for PureScript.
For a more high-level set of bindings, you might like to look at purescript-thermite
.
bower install purescript-react
This library requires the react
module. This dependency may be satisfied by installing the NPM react package.
npm install react
Please refer to purescript-react-example
To use a React component that is published as a JavaScript module, one can leverage PureScript's FFI to define a type for the component and its props. Consider the following example.
module Clock (clockComponent) where
import React (ReactClass, SyntheticEventHandler, Children)
import React.SyntheticEvent (SyntheticEvent)
foreign import clockComponent
:: ReactClass
{ children :: Children
, format :: String
, className :: String
, onTick :: SyntheticEventHandler SyntheticEvent
}
Rendering the clockComponent
can be done as follows.
module Component where
import Prelude
import Effect.Uncurried (mkEffectFn1)
import React as React
import React.SyntheticEvent as Event
import Clock as Clock
clock :: React.ReactElement
clock =
React.createElement Clock.clockComponent
{ format: "HH:mm:ss"
, className: "test-class-name"
, onTick: mkEffectFn1 $ \event -> do
Event.preventDefault event
-- etc.
pure unit
} []
A consideration when defining a type for an external component is that
some components pass their props through to a DOM element. In a case
such as this, it can be helpful to leverage the props defined in the
React.DOM.Props
module. One way to accomplish this is to define the
external component as follows.
module Clock
( clockComponent
, format
, onTick
) where
import Prelude
import Effect (Effect)
import Effect.Uncurried (mkEffectFn1)
import React (ReactClass, ReactElement, Children, createElement)
import React.SyntheticEvent (SyntheticEvent)
import React.DOM.Props (Props, unsafeFromPropsArray, unsafeMkProps)
clockComponent :: Array Props -> Array ReactElement -> ReactElement
clockComponent props children = createElement clockComponent_ (unsafeFromPropsArray props :: {}) children
format :: String -> Props
format = unsafeMkProps "format"
onTick :: (SyntheticEvent -> Effect Unit) -> Props
onTick k = unsafeMkProps "onTick" (mkEffectFn1 k)
foreign import clockComponent_
:: ReactClass
{ children :: Children
}
Rendering the clockComponent
can be done as follows.
module Component where
import Prelude
import React as React
import React.SyntheticEvent as Event
import React.DOM.Props as Props
import Clock as Clock
clock :: React.ReactElement
clock =
Clock.clockComponent
[ Clock.format "HH:mm:ss"
, Clock.onTick $ \event -> do
Event.preventDefault event
-- etc.
pure unit
, Props.className "test-class-name"
, Props.style
{ fontWeight: "bold"
, color: "blue"
}
-- additional Props.*
]
[ ]
Consider the following example where an ordered list component is
defined for any item of type a
, where a
is constrained to have an
Ord
type class instance.
module OrderedList where
import Prelude
import Data.Array (sort)
import React as React
import React.DOM as DOM
import Debug.Trace as Trace
type OrderedListProps a
= { items :: Array a
, renderItem :: a -> React.ReactElement
}
orderedList :: forall a. Ord a => React.ReactClass (OrderedListProps a)
orderedList = React.component "OrderedList" component
where
component this =
pure { state: {}
, componentDidMount: do
_ <- pure $ Trace.spy "OrderedList.componentDidMount"
pure unit
, render: render <$> React.getProps this
}
where
render
{ items
, renderItem
} =
DOM.ol [ ] $
renderItem' <$> sort items
where
renderItem' a =
DOM.li
[ ]
[ renderItem a ]
-- This would be defined where the type parameter `a` is known.
orderedListInt :: React.ReactClass (OrderedListProps Int)
orderedListInt = orderedList
If the component orderedList
above were to be rendered, the debugging
statement OrderedList.componentDidMount
is printed to the console each
time the parent component is rendered. The reason for this is due to how
the orderedList
component is compiled to JavaScript.
var orderedList = function (dictOrd) {
var component = function ($$this) {
// ...
};
return React.component(React.reactComponentSpec()())("OrderedList")(component);
};
Above, the component creation is wrapped by the function with the
dictOrd
parameter. This means that a new component is being created on
each render of the component using orderedList
. This may not be ideal
in all cases; e.g., if orderedList
had needed to store state.
To avoid orderedList
from being recreated each time, a function can be
defined that specifies the type parameter with the type class contraint.
If the component using the ordered list knows that the items are of type
Int
, the component can define orderedListInt
as shown above, and use
it to render the ordered list instead of orderedList
.