@@ -2,47 +2,103 @@ module AffEx where
2
2
3
3
import Prelude
4
4
5
- import Data.Either (Either (..) )
6
- import Data.Maybe (Maybe (..))
5
+ import Data.Either (either )
6
+ import Data.Maybe (Maybe (..), maybe )
7
7
import Effect.Aff (Aff , Milliseconds (..), delay , error , message , throwError )
8
8
import React.Basic.DOM as R
9
9
import 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 , (/\))
11
11
import React.Basic.Hooks as React
12
12
import React.Basic.Hooks.Aff (useAff )
13
- import React.Basic.Hooks.ResetToken (useResetToken )
14
13
15
14
mkAffEx :: CreateComponent { }
16
15
mkAffEx = do
16
+ -- A component for fetching and rendering a Cat entity.
17
+ catDetails <- mkCatDetails
18
+
17
19
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
+ }
31
40
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"
38
66
]
39
67
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 }
44
93
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