@@ -5,73 +5,95 @@ import Data.Foldable (find)
55import Data.Maybe (Maybe (..))
66import Data.Newtype (class Newtype , un )
77import Effect (Effect )
8- import Effect.Aff (Aff , Milliseconds (..), delay , error , throwError )
8+ import Effect.Aff (Aff , Milliseconds (..), delay , error , message , throwError )
99import React.Basic.DOM as R
10+ import React.Basic.DOM.Events (capture_ )
1011import React.Basic.Events (handler_ )
11- import React.Basic.Hooks (type (/\) , ReactComponent , Hook , JSX , component , element , fragment , useState , (/\))
12+ import React.Basic.Hooks (JSX , ReactComponent , component , element , fragment , useState , (/\))
1213import React.Basic.Hooks as React
1314import React.Basic.Hooks.Aff (useAff )
15+ import React.Basic.Hooks.ErrorBoundary (mkErrorBoundary )
1416
1517mkExample :: Effect (ReactComponent { } )
1618mkExample = do
17- -- A component for fetching and rendering a Cat entity.
19+ errorBoundary <- mkErrorBoundary " AffExErrorBoundary "
1820 catDetails <- mkCatDetails
1921 component " AffEx" \props -> React .do
20- catKey /\ catChooser <- useCatKeyChooser
22+ catKey /\ setCatKey <- useState Nothing
23+ let
24+ reset = setCatKey \_ -> Nothing
2125 pure
22- $ 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
26+ $ R .div_
27+ [ R .h2_ [ R .text " Cat chooser" ]
28+ , errorBoundary \{ error, dismissError } -> case error of
29+ Just e -> renderAppError e (reset *> dismissError)
30+ Nothing ->
31+ fragment
32+ [ catKeyList catKey setCatKey
33+ , case catKey of
3534 Nothing -> mempty
36- Just k -> element catDetails { catKey: k }
35+ Just k -> catDetails { catKey: k }
3736 ]
37+ ]
38+ where
39+ -- This component is the main `useAff` demo. It receives a key
40+ -- as a prop and renders both the loading state and the final
41+ -- result.
42+ mkCatDetails :: Effect ({ catKey :: Key Cat } -> JSX )
43+ mkCatDetails =
44+ map element do
45+ component " CatDetails" \{ catKey } -> React .do
46+ catState <- useAff catKey $ fetch catKey
47+ pure
48+ $ R .p_
49+ [ case map entity catState of
50+ Nothing -> R .text " Loading..."
51+ Just (Cat { name }) -> R .text $ " A cat named " <> name
3852 ]
53+
54+ renderAppError error resetApp =
55+ fragment
56+ [ R .p_ [ R .text " Error!" ]
57+ , R .p_ [ R .text $ message error ]
58+ , R .button
59+ { onClick: capture_ do resetApp
60+ , children: [ R .text " Reset" ]
3961 }
40- where
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 k =
48- R .label_
49- [ R .input
50- { type: " radio"
51- , name: " cat-key"
52- , checked: Just k == catKey
53- , onChange:
54- handler_ do
55- setCatKey \_ -> Just k
56- }
57- , R .text $ " " <> showCatKey k
58- ]
62+ ]
5963
60- showCatKey :: Key Cat -> String
61- showCatKey (Key k) = " Cat " <> k
62- pure $ catKey /\ fragment (map (catChoice <<< key) fakeDb)
64+ catKeyList selectedCatKey setCatKey =
65+ let
66+ cats =
67+ fakeDb
68+ <> [ Entity
69+ (Key " error (choose to throw a React render error)" )
70+ (Cat { name: " " })
71+ ]
6372
64- -- Hooks can't be used conditionally but components can!
65- -- Not needing to deal with a `Maybe` key simplifies this
66- -- compoennt a bit.
67- mkCatDetails :: Effect (ReactComponent { catKey :: Key Cat } )
68- mkCatDetails = do
69- component " CatDetails" \{ catKey } -> React .do
70- catState <- useAff catKey $ fetch catKey
71- pure case map entity catState of
72- Nothing -> R .text " Loading..."
73- Just (Cat { name }) -> R .text $ " A cat named " <> name
73+ catKeyRadioButton k =
74+ R .div_
75+ [ R .label_
76+ [ R .input
77+ { type: " radio"
78+ , name: " cat-key"
79+ , checked: Just k == selectedCatKey
80+ , onChange:
81+ handler_ do
82+ setCatKey \_ -> Just k
83+ }
84+ , R .text $ " Cat " <> un Key k
85+ ]
86+ ]
87+ in
88+ fragment $ map (catKeyRadioButton <<< key) cats
7489
90+ --
91+ -- The bits below this point aren't directly relevant to the example,
92+ -- just a slightly more interesting data model than returing a single
93+ -- string.
94+ --
95+ --
96+ --
7597-- Typed keys are a great way to tie entity-specific behavior
7698-- to an ID. We can use this phantom type to write a class
7799-- for generic, type-safe data fetching.
0 commit comments