@@ -2,47 +2,103 @@ module AffEx where
22
33import Prelude
44
5- import Data.Either (Either (..) )
6- import Data.Maybe (Maybe (..))
5+ import Data.Either (either )
6+ import Data.Maybe (Maybe (..), maybe )
77import Effect.Aff (Aff , Milliseconds (..), delay , error , message , throwError )
88import React.Basic.DOM as R
99import React.Basic.Events (handler_ )
10- import React.Basic.Hooks (CreateComponent , component , fragment , (/\))
10+ import React.Basic.Hooks (type (/\), CreateComponent , Hook , JSX , component , element , fragment , useState , (/\))
1111import React.Basic.Hooks as React
1212import React.Basic.Hooks.Aff (useAff )
13- import React.Basic.Hooks.ResetToken (useResetToken )
1413
1514mkAffEx :: CreateComponent { }
1615mkAffEx = do
16+ -- A component for fetching and rendering a Cat entity.
17+ catDetails <- mkCatDetails
18+
1719 component " AffEx" \props -> React .do
18- let id = 0 -- pretend this is a prop
19- resetToken /\ reset <- useResetToken
20- r1 <- useAff (id /\ resetToken) delayedSuccess
21- r2 <- useAff (id /\ resetToken) delayedFailure
22-
23- pure $ fragment
24- [ R .button
25- { onClick: handler_ reset
26- , children: [ R .text " Reset" ]
27- }
28- , showResult 1 r1
29- , showResult 2 r2
30- ]
20+ catKey /\ catChooser <- useCatKeyChooser
21+
22+ pure $ R .div
23+ { style: R .css { display: " flex" , flexFlow: " column" }
24+ , children:
25+ [ R .h2_ [ R .text " Cat chooser" ]
26+ , R .p_
27+ [ R .text $
28+ " Select a key to fetch! If you get bored (how would you even!?) " <>
29+ " try holding your arrow keys to select really fast! The result " <>
30+ " always matches the chosen key."
31+ ]
32+ , catChooser
33+ , R .p_
34+ [ case catKey of
35+ Nothing -> mempty
36+ Just k -> element catDetails { catKey: k }
37+ ]
38+ ]
39+ }
3140 where
32- showResult n r =
33- R .div_
34- [ R .text $ " Request " <> show n <> " : " <> case r of
35- Nothing -> " loading..."
36- Just (Left err) -> message err
37- Just (Right msg) -> msg
41+ -- This hook packages up some interactive UI and the current
42+ -- selection the user has made via that UI.
43+ useCatKeyChooser :: Hook _ ((Maybe (Key Cat )) /\ JSX )
44+ useCatKeyChooser = React .do
45+ catKey /\ setCatKey <- useState Nothing
46+ let
47+ catChoice key =
48+ R .label_
49+ [ R .input
50+ { type: " radio"
51+ , name: " cat-key"
52+ , checked: Just key == catKey
53+ , onChange: handler_ do
54+ setCatKey \_ -> Just key
55+ }
56+ , R .text $ showCatKey key
57+ ]
58+
59+ showCatKey :: Key Cat -> String
60+ showCatKey (Key key) = " Cat " <> key
61+
62+ pure $ catKey /\ fragment
63+ [ catChoice $ Key " abc"
64+ , catChoice $ Key " def"
65+ , catChoice $ Key " xyz"
3866 ]
3967
40- delayedSuccess :: Aff String
41- delayedSuccess = do
42- delay $ Milliseconds 1000.0
43- pure " Success!"
68+ -- Hooks can't be used conditionally but components can!
69+ -- Not needing to deal with a `Maybe` key simplifies this
70+ -- compoennt a bit.
71+ mkCatDetails :: CreateComponent { catKey :: Key Cat }
72+ mkCatDetails = do
73+ component " CatDetails" \{ catKey } -> React .do
74+ cat <- useAff catKey $ fetch catKey
75+ pure $ R .text $
76+ maybe " Loading..." (either message showCat) cat
77+ where
78+ showCat (Cat { name }) = " A cat named " <> name
79+
80+
81+ -- Typed keys are a great way to tie entity-specific behavior
82+ -- to an ID. We can use this phantom type to write a class
83+ -- for generic, type-safe data fetching.
84+ newtype Key entity = Key String
85+ derive instance eqKey :: Eq (Key entity )
86+
87+ class Fetch entity where
88+ fetch :: Key entity -> Aff entity
89+
90+
91+ -- An example entity
92+ newtype Cat = Cat { name :: String }
4493
45- delayedFailure :: Aff String
46- delayedFailure = do
47- delay $ Milliseconds 2000.0
48- throwError $ error " Failure!"
94+ instance fetchCat :: Fetch Cat where
95+ fetch = case _ of
96+ Key " abc" -> do
97+ delay $ Milliseconds 300.0
98+ pure $ Cat { name: " Herb" }
99+ Key " def" -> do
100+ delay $ Milliseconds 600.0
101+ pure $ Cat { name: " Maxi" }
102+ _ -> do
103+ delay $ Milliseconds 900.0
104+ throwError $ error " Cat not found (intended example behavior 😅)"
0 commit comments