-
Notifications
You must be signed in to change notification settings - Fork 34
/
Copy pathSuspense.purs
62 lines (53 loc) · 2.08 KB
/
Suspense.purs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
module React.Basic.Hooks.Suspense
( suspend
, Suspended(..)
, SuspenseResult(..)
, suspense
) where
import Prelude
import Control.Promise (Promise)
import Control.Promise as Promise
import Effect (Effect)
import Effect.Aff (Error, Fiber, joinFiber, throwError)
import React.Basic.Hooks (JSX, Pure, ReactComponent, element, unsafeRenderEffect)
import Unsafe.Coerce (unsafeCoerce)
-- | Suspend rendering until a result exists.
-- |
-- | *Note: Error and loading states are thrown to React! Don't forget
-- | to implement a React error boundary and ensure `suspend` is
-- | only called from a child of at least one `suspense` parent!*
-- |
-- | *Note: You probably shouldn't be using this function directly. It's
-- | primarily for library authors to build abstractions on top of, as
-- | it requires things like caching mechanisms external to the
-- | component tree.*
-- |
-- | *Warning: React's Suspense API is still experimental. It requires
-- | some manual setup as well as specific versions of React. The API
-- | is also not final and these functions may change.*
suspend :: forall a. Suspended a -> Pure a
suspend (Suspended e) = React.do
unsafeRenderEffect do
result <- e
case result of
InProgress fiber ->
unsafeThrowPromise
=<< Promise.fromAff (joinFiber fiber)
Failed err -> throwError err
Complete a -> pure a
newtype Suspended a
= Suspended (Effect (SuspenseResult a))
derive instance functorSuspended :: Functor Suspended
data SuspenseResult a
= InProgress (Fiber a)
| Failed Error
| Complete a
derive instance functorSuspenseResult :: Functor SuspenseResult
suspense :: { fallback :: JSX, children :: Array JSX } -> JSX
suspense = element suspense_
foreign import suspense_ :: ReactComponent { children :: Array JSX, fallback :: JSX }
-- | Dangerously throw a `Promise` as though it were an `Error`.
-- | React's Suspense API catches thrown `Promise`s and suspends
-- | rendering until they complete.
unsafeThrowPromise :: forall a. Promise a -> Effect a
unsafeThrowPromise = throwError <<< (unsafeCoerce :: Promise a -> Error)