Safe Haskell | None |
---|---|
Language | Haskell2010 |
This module contains some useful combinators I have come across as I built a large react-flux application. None of these are required to use React.Flux, they just reduce somewhat the typing needed to create rendering functions.
- clbutton_ :: String -> handler -> ReactElementM handler a -> ReactElementM handler a
- cldiv_ :: String -> ReactElementM handler a -> ReactElementM handler a
- faIcon_ :: String -> ReactElementM handler ()
- foreign_ :: String -> [PropertyOrHandler handler] -> ReactElementM handler a -> ReactElementM handler a
- labeledInput_ :: String -> ReactElementM handler () -> [PropertyOrHandler handler] -> ReactElementM handler ()
- initAjax :: IO ()
- jsonAjax :: (ToJSON body, FromJSON response) => Text -> Text -> [(Text, Text)] -> body -> (Either (Int, Text) response -> IO [SomeStoreAction]) -> IO ()
- data AjaxRequest = AjaxRequest {
- reqMethod :: JSString
- reqURI :: JSString
- reqHeaders :: [(JSString, JSString)]
- reqBody :: JSVal
- data AjaxResponse = AjaxResponse {
- respStatus :: Int
- respResponseText :: JSString
- respResponseXHR :: JSVal
- ajax :: AjaxRequest -> (AjaxResponse -> IO [SomeStoreAction]) -> IO ()
Documentation
:: String | class names separated by spaces |
-> handler | the onClick handler for the button |
-> ReactElementM handler a | the children |
-> ReactElementM handler a |
cldiv_ :: String -> ReactElementM handler a -> ReactElementM handler a Source
A div_
with the given class name (multiple classes can be separated by spaces). This is
useful for defining rows and columns in your CSS framework of choice. I use
Pure CSS so I use it something like:
cldiv_ "pure-g" $ do cldiv_ "pure-u-1-3" $ p_ "First Third" cldiv_ "pure-u-1-3" $ p_ "Middle Third" cldiv_ "pure-u-1-3" $ p_ "Last Third"
You should consider writing something like the following for the various components in your frontend of choice. In PureCSS, I use:
prow_ :: ReactElementM handler a -> ReactElementM handler a prow_ = cldiv_ "pure-g" pcol_ :: String -> ReactElementM handler a -> ReactElementM handler a pcol_ cl = cldiv_ (unwords $ map ("pure-u-"++) $ words cl)
faIcon_ :: String -> ReactElementM handler () Source
A Font Awesome icon. The given string is prefixed
by `fa fa-` and then used as the class for an i
element. This allows you to icons such as
faIcon_ "fighter-jet" -- produces <i class="fa fa-fighter-jet"> faIcon_ "refresh fa-spin" -- produces <i class="fa fa-refresh fa-spin">
:: String | this should be the name of a property on |
-> [PropertyOrHandler handler] | properties |
-> ReactElementM handler a | children |
-> ReactElementM handler a |
A wrapper around foreignClass
that looks up the class on the window
. I use it for several
third-party react components. For example, with react-modal,
assuming `window.ReactModal` contains the definition of the class,
foreign_ "ReactModal" [ "isOpen" @= isModelOpen myProps , callback "onRequestClose" $ dispatch closeModel , "style" @= Aeson.object [ "overlay" @= Aeson.object ["left" $= "50%", "right" $= "50%"]] ] $ do h1_ "Hello, World!" p_ "...."
Here is another example using react-select:
reactSelect_ :: [PropertyOrHandler eventHandler] -> ReactElementM eventHandler () reactSelect_ props = foreign_ "Select" props mempty someView :: ReactView () someView = defineView "some view" $ \() -> reactSelect_ [ "name" $= "form-field-name" , "value" $= "one" , "options" @= [ object [ "value" .= "one", "label" .= "One" ] , object [ "value" .= "two", "label" .= "Two" ] ] , callback "onChange" $ \(i :: String) -> dispatch $ ItemChangedTo i ]
:: String | the ID for the input element |
-> ReactElementM handler () | the label content. This is wrapped in a |
-> [PropertyOrHandler handler] | the properties to pass to |
-> ReactElementM handler () |
A label_
and an input_
together. Useful for laying out forms. For example, a
stacked Pure CSS Form could be
form_ ["className" $= "pure-form pure-form-stacked"] $ fieldset_ $ do legend_ "A stacked form" labeledInput_ "email" "Email" ["type" $= "email"] labeledInput_ "password" ($(message "password-label" "Your password") []) ["type" $= "password"]
The second labeledInput_
shows an example using React.Flux.Addons.Intl.
Ajax
:: (ToJSON body, FromJSON response) | |
=> Text | the method |
-> Text | the URI |
-> [(Text, Text)] | the headers. In addition to these headers, |
-> body | the body |
-> (Either (Int, Text) response -> IO [SomeStoreAction]) | Once
|
-> IO () |
Use XMLHttpRequest
to send a request with a JSON body, parse the response body as JSON, and
then dispatch some actions with the response. This should be used from within the transform
function of your store. For example,
data Target = AlienShip | AlienPlanet deriving (Show, Typeable, Generic, ToJSON, FromJSON) data Trajectory = Trajectory { x :: Double, y :: Double, z :: Double, vx :: Double, vy :: Double, vz :: Double } deriving (Show, Typeable, Generic, ToJSON, FromJSON) data UpdatePending = NoUpdatePending | UpdatePending Text | PreviousUpdateHadError Text data MyStore = MyStore { currentTrajectory :: Maybe Trajectory, launchUpdate :: UpdatePending } data MyStoreAction = LaunchTheMissiles Target | MissilesLaunched Trajectory | UnableToLaunchMissiles Text deriving (Typeable, Generic, NFData) instance StoreData MyStore where type StoreAction MyStore = MyStoreAction transform (LaunchTheMissiles t) s = do jsonAjax "PUT" "/launch-the-missiles" [] t $ \case Left (_, msg) -> return [SomeStoreAction myStore $ UnableToLaunchMissiles msg] Right traj -> return [SomeStoreAction myStore $ MissilesLaunched traj] return s { launchUpdate = UpdatePending ("Requesting missle launch against " ++ T.pack (show t)) } transform (MissilesLaunched traj) s = return s { currentTrajectory = Just traj, launchUpdate = NoUpdatePending } transform (UnableToLaunchMissiles err) s = return s { launchUpdate = PreviousUpdateHadError err } myStore :: ReactStore MyStore myStore = mkStore $ MyStore Nothing NoUpdatePending
And then in your view, you can render this using something like:
myView :: ReactView () myView = defineControllerView "launch the missles" myStore $ \s () -> do case launchUpdate s of NoUpdatePending -> return () UpdatePending msg -> span_ $ faIcon_ "rocket" <> elemText (T.unpack msg) PreviousUpdateHadErroer err -> span_ $ faIcon_ "exclamation" <> elemText (T.unpack err) clbutton_ ["pure-button button-success"] ([SomeStoreAction myStore $ LaunchTheMissiles AlienShip]) $ do faIcon_ "rocket" "Launch the missles against the alien ship!" p_ $ elemText $ "Current trajectory " ++ show (currentTrajectory s)
data AjaxRequest Source
The input to an AJAX request built using XMLHttpRequest
.
AjaxRequest | |
|
data AjaxResponse Source
The response after XMLHttpRequest
indicates that the readyState
is done.
AjaxResponse | |
|
ajax :: AjaxRequest -> (AjaxResponse -> IO [SomeStoreAction]) -> IO () Source
Use XMLHttpRequest
to send a request to the backend. Once the response arrives
and the readyState
is done, the response will be passed to the given handler and the resulting
actions will be executed. Note that ajax
returns immedietly and does not wait for the request
to finish.