|
| 1 | +module React.Redux |
| 2 | + ( ReduxReactClass |
| 3 | + , Effects |
| 4 | + , REDUX |
| 5 | + , Reducer |
| 6 | + , Store |
| 7 | + , createClass |
| 8 | + , createElement |
| 9 | + , createStore |
| 10 | + , reducerOptic |
| 11 | + |
| 12 | + , Spec |
| 13 | + , Render |
| 14 | + , GetInitialState |
| 15 | + , ComponentWillMount |
| 16 | + , ComponentDidMount |
| 17 | + , ComponentWillReceiveProps |
| 18 | + , ShouldComponentUpdate |
| 19 | + , ComponentWillUpdate |
| 20 | + , ComponentDidUpdate |
| 21 | + , ComponentWillUnmount |
| 22 | + , spec |
| 23 | + , spec' |
| 24 | + ) where |
| 25 | + |
| 26 | +import Prelude (Unit, (<<<), (>>=), const, pure, unit) |
| 27 | + |
| 28 | +import Control.Monad.Eff (Eff) |
| 29 | +import Control.Monad.Eff.Class (class MonadEff, liftEff) |
| 30 | + |
| 31 | +import Data.Either (Either, either) |
| 32 | +import Data.Function (Fn2, runFn2) |
| 33 | +import Data.Lens (GetterP, LensP, PrismP, matching, set, view) |
| 34 | + |
| 35 | +import Unsafe.Coerce (unsafeCoerce) |
| 36 | + |
| 37 | +import React as React |
| 38 | + |
| 39 | +type Reducer action state = action -> state -> state |
| 40 | + |
| 41 | +type Effects eff = (redux :: REDUX | eff) |
| 42 | + |
| 43 | +type Render props state eff f action = (f action -> f action) -> React.Render props state eff |
| 44 | + |
| 45 | +type GetInitialState props state eff f action = (f action -> f action) -> React.GetInitialState props state eff |
| 46 | + |
| 47 | +type ComponentWillMount props state eff f action = (f action -> f action) -> React.ComponentWillMount props state eff |
| 48 | + |
| 49 | +type ComponentDidMount props state eff f action = (f action -> f action) -> React.ComponentDidMount props state eff |
| 50 | + |
| 51 | +type ComponentWillReceiveProps props state eff f action = (f action -> f action) -> React.ComponentWillReceiveProps props state eff |
| 52 | + |
| 53 | +type ShouldComponentUpdate props state eff f action = (f action -> f action) -> React.ShouldComponentUpdate props state eff |
| 54 | + |
| 55 | +type ComponentWillUpdate props state eff f action = (f action -> f action) -> React.ComponentWillUpdate props state eff |
| 56 | + |
| 57 | +type ComponentDidUpdate props state eff f action = (f action -> f action) -> React.ComponentDidUpdate props state eff |
| 58 | + |
| 59 | +type ComponentWillUnmount props state eff f action = (f action -> f action) -> React.ComponentWillUnmount props state eff |
| 60 | + |
| 61 | +type Spec props state eff f action = |
| 62 | + { render :: Render props state eff f action |
| 63 | + , displayName :: String |
| 64 | + , getInitialState :: GetInitialState props state eff f action |
| 65 | + , componentWillMount :: ComponentWillMount props state eff f action |
| 66 | + , componentDidMount :: ComponentDidMount props state eff f action |
| 67 | + , componentWillReceiveProps :: ComponentWillReceiveProps props state eff f action |
| 68 | + , shouldComponentUpdate :: ShouldComponentUpdate props state eff f action |
| 69 | + , componentWillUpdate :: ComponentWillUpdate props state eff f action |
| 70 | + , componentDidUpdate :: ComponentDidUpdate props state eff f action |
| 71 | + , componentWillUnmount :: ComponentWillUnmount props state eff f action |
| 72 | + } |
| 73 | + |
| 74 | +spec :: |
| 75 | + forall props state eff f action. |
| 76 | + GetInitialState props state eff f action -> |
| 77 | + Render props state eff f action -> |
| 78 | + Spec props state eff f action |
| 79 | +spec getInitialState render = |
| 80 | + { render: render |
| 81 | + , displayName: "" |
| 82 | + , getInitialState: getInitialState |
| 83 | + , componentWillMount: \_ _ -> pure unit |
| 84 | + , componentDidMount: \_ _ -> pure unit |
| 85 | + , componentWillReceiveProps: \_ _ _ -> pure unit |
| 86 | + , shouldComponentUpdate: \_ _ _ _ -> pure true |
| 87 | + , componentWillUpdate: \_ _ _ _ -> pure unit |
| 88 | + , componentDidUpdate: \_ _ _ _ -> pure unit |
| 89 | + , componentWillUnmount: \_ _ -> pure unit |
| 90 | + } |
| 91 | + |
| 92 | +spec' :: forall props eff f action. Render props Unit eff f action -> Spec props Unit eff f action |
| 93 | +spec' = spec (\_ _ -> pure unit) |
| 94 | + |
| 95 | +createClass :: forall props state eff f action state'. MonadEff (Effects eff) f => GetterP state' props -> Spec props state eff f action -> ReduxReactClass state' props |
| 96 | +createClass lens spec_ = connect (view lens) reactClass |
| 97 | + where |
| 98 | + reactClass :: React.ReactClass props |
| 99 | + reactClass = |
| 100 | + React.createClass { render: \this -> spec_.render (dispatch this) this |
| 101 | + , displayName: spec_.displayName |
| 102 | + , getInitialState: \this -> spec_.getInitialState (dispatch this) this |
| 103 | + , componentWillMount: \this -> spec_.componentWillMount (dispatch this) this |
| 104 | + , componentDidMount: \this -> spec_.componentDidMount (dispatch this) this |
| 105 | + , componentWillReceiveProps: \this -> spec_.componentWillReceiveProps (dispatch this) this |
| 106 | + , shouldComponentUpdate: \this -> spec_.shouldComponentUpdate (dispatch this) this |
| 107 | + , componentWillUpdate: \this -> spec_.componentWillUpdate (dispatch this) this |
| 108 | + , componentDidUpdate: \this -> spec_.componentDidUpdate (dispatch this) this |
| 109 | + , componentWillUnmount: \this -> spec_.componentWillUnmount (dispatch this) this |
| 110 | + } |
| 111 | + where |
| 112 | + dispatch :: React.ReactThis props state -> f action -> f action |
| 113 | + dispatch this action = action >>= liftEff <<< runFn2 dispatch_ this |
| 114 | + |
| 115 | +createElement :: forall props action state'. Store action state' -> ReduxReactClass state' props -> React.ReactElement |
| 116 | +createElement store reduxClass = |
| 117 | + React.createElement providerClass { store: store } [ reduxEl ] |
| 118 | + where |
| 119 | + reduxEl :: React.ReactElement |
| 120 | + reduxEl = React.createElement (unsafeCoerce reduxClass) (unsafeCoerce unit) [] |
| 121 | + |
| 122 | +createStore :: forall eff action state. Reducer action state -> state -> Eff (Effects eff) (Store action state) |
| 123 | +createStore = runFn2 createStore_ |
| 124 | + |
| 125 | +reducerOptic :: forall state state' action action'. LensP state state' -> PrismP action action' -> Reducer action' state' -> Reducer action state |
| 126 | +reducerOptic lens prism k action state = either (const state) (\a -> set lens (k a state') state) action' |
| 127 | + where |
| 128 | + state' :: state' |
| 129 | + state' = view lens state |
| 130 | + |
| 131 | + action' :: Either action action' |
| 132 | + action' = matching prism action |
| 133 | + |
| 134 | +foreign import data REDUX :: ! |
| 135 | + |
| 136 | +foreign import data Store :: * -> * -> * |
| 137 | + |
| 138 | +foreign import data ReduxReactClass :: * -> * -> * |
| 139 | + |
| 140 | +foreign import connect :: forall state' props. (state' -> props) -> React.ReactClass props -> ReduxReactClass state' props |
| 141 | + |
| 142 | +foreign import dispatch_ :: forall eff props action state. Fn2 (React.ReactThis props state) action (Eff (Effects eff) action) |
| 143 | + |
| 144 | +foreign import providerClass :: forall action state'. React.ReactClass { store :: Store action state' } |
| 145 | + |
| 146 | +foreign import createStore_ :: forall eff action state. Fn2 (Reducer action state) state (Eff (Effects eff) (Store action state)) |
0 commit comments