Skip to content

Initial implementation #1

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 15, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
Copyright (c) 2016 Eric Thul

Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the
"Software"), in the Software without restriction, including without
limitation the rights to use, copy, modify, merge, publish, distribute,
sublicense, and/or sell copies of the Software, and to permit persons to
whom the Software is furnished to do so, subject to the following
conditions:

The above copyright notice and this permission notice shall be included
in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# purescript-react-redux

A library for using [Redux with React](http://redux.js.org/docs/basics/UsageWithReact.html).

## Installation

```bash
bower install --save purescript-react-redux
```

## Example

Refer to the [purescript-react-redux-example](https://github.com/ethul/purescript-react-redux-example) for an example.
18 changes: 16 additions & 2 deletions bower.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,22 @@
{
"name": "purescript-react-redux",
"private": true,
"description": "PureScript library for using Redux with React",
"keywords": [
"purescript",
"react",
"redux"
],
"license": "MIT",
"repository": {
"type": "git",
"url": "git://github.com/ethul/purescript-react-redux.git"
},
"ignore": [
"*",
"!src/**/*"
]
],
"dependencies": {
"purescript-profunctor-lenses": "~0.5.4",
"purescript-react": "~0.7.1"
}
}
11 changes: 10 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,14 @@
"name": "purescript-react-redux",
"version": "0.1.0",
"private": true,
"files": []
"files": [],
"scripts": {
"psc:server": "psc-ide-server --port 4291 --debug",
"psc:watch": "pscid -p 4291",
"build": "pulp build --force"
},
"devDependencies": {
"pscid": "^1.7.3",
"purescript": "^0.8.5"
}
}
40 changes: 40 additions & 0 deletions src/React/Redux.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
'use strict';

// module React.Redux

var Redux = require('redux');

var ReactRedux = require('react-redux');

function createStore_(reducer, state) {
return function(){
function reducer_(state, action){
var action_ = action.action;
return action_ === undefined ? state : reducer(action_)(state);
};

return Redux.createStore(reducer_, state);
};
}
exports.createStore_ = createStore_;

function connect(stateToProps) {
return ReactRedux.connect(stateToProps);
}
exports.connect = connect;

function dispatch_(this_, action){
return function(){
var action_ = {
type: '@@purescript',
action: action
};

var result = this_.props.dispatch(action_);

return result.action;
};
}
exports.dispatch_ = dispatch_;

exports.providerClass = ReactRedux.Provider;
146 changes: 146 additions & 0 deletions src/React/Redux.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
module React.Redux
( ReduxReactClass
, Effects
, REDUX
, Reducer
, Store
, createClass
, createElement
, createStore
, reducerOptic

, Spec
, Render
, GetInitialState
, ComponentWillMount
, ComponentDidMount
, ComponentWillReceiveProps
, ShouldComponentUpdate
, ComponentWillUpdate
, ComponentDidUpdate
, ComponentWillUnmount
, spec
, spec'
) where

import Prelude (Unit, (<<<), (>>=), const, pure, unit)

import Control.Monad.Eff (Eff)
import Control.Monad.Eff.Class (class MonadEff, liftEff)

import Data.Either (Either, either)
import Data.Function (Fn2, runFn2)
import Data.Lens (GetterP, LensP, PrismP, matching, set, view)

import Unsafe.Coerce (unsafeCoerce)

import React as React

type Reducer action state = action -> state -> state

type Effects eff = (redux :: REDUX | eff)

type Render props state eff f action = (f action -> f action) -> React.Render props state eff

type GetInitialState props state eff f action = (f action -> f action) -> React.GetInitialState props state eff

type ComponentWillMount props state eff f action = (f action -> f action) -> React.ComponentWillMount props state eff

type ComponentDidMount props state eff f action = (f action -> f action) -> React.ComponentDidMount props state eff

type ComponentWillReceiveProps props state eff f action = (f action -> f action) -> React.ComponentWillReceiveProps props state eff

type ShouldComponentUpdate props state eff f action = (f action -> f action) -> React.ShouldComponentUpdate props state eff

type ComponentWillUpdate props state eff f action = (f action -> f action) -> React.ComponentWillUpdate props state eff

type ComponentDidUpdate props state eff f action = (f action -> f action) -> React.ComponentDidUpdate props state eff

type ComponentWillUnmount props state eff f action = (f action -> f action) -> React.ComponentWillUnmount props state eff

type Spec props state eff f action =
{ render :: Render props state eff f action
, displayName :: String
, getInitialState :: GetInitialState props state eff f action
, componentWillMount :: ComponentWillMount props state eff f action
, componentDidMount :: ComponentDidMount props state eff f action
, componentWillReceiveProps :: ComponentWillReceiveProps props state eff f action
, shouldComponentUpdate :: ShouldComponentUpdate props state eff f action
, componentWillUpdate :: ComponentWillUpdate props state eff f action
, componentDidUpdate :: ComponentDidUpdate props state eff f action
, componentWillUnmount :: ComponentWillUnmount props state eff f action
}

spec ::
forall props state eff f action.
GetInitialState props state eff f action ->
Render props state eff f action ->
Spec props state eff f action
spec getInitialState render =
{ render: render
, displayName: ""
, getInitialState: getInitialState
, componentWillMount: \_ _ -> pure unit
, componentDidMount: \_ _ -> pure unit
, componentWillReceiveProps: \_ _ _ -> pure unit
, shouldComponentUpdate: \_ _ _ _ -> pure true
, componentWillUpdate: \_ _ _ _ -> pure unit
, componentDidUpdate: \_ _ _ _ -> pure unit
, componentWillUnmount: \_ _ -> pure unit
}

spec' :: forall props eff f action. Render props Unit eff f action -> Spec props Unit eff f action
spec' = spec (\_ _ -> pure unit)

createClass :: forall props state eff f action state'. MonadEff (Effects eff) f => GetterP state' props -> Spec props state eff f action -> ReduxReactClass state' props
createClass lens spec_ = connect (view lens) reactClass
where
reactClass :: React.ReactClass props
reactClass =
React.createClass { render: \this -> spec_.render (dispatch this) this
, displayName: spec_.displayName
, getInitialState: \this -> spec_.getInitialState (dispatch this) this
, componentWillMount: \this -> spec_.componentWillMount (dispatch this) this
, componentDidMount: \this -> spec_.componentDidMount (dispatch this) this
, componentWillReceiveProps: \this -> spec_.componentWillReceiveProps (dispatch this) this
, shouldComponentUpdate: \this -> spec_.shouldComponentUpdate (dispatch this) this
, componentWillUpdate: \this -> spec_.componentWillUpdate (dispatch this) this
, componentDidUpdate: \this -> spec_.componentDidUpdate (dispatch this) this
, componentWillUnmount: \this -> spec_.componentWillUnmount (dispatch this) this
}
where
dispatch :: React.ReactThis props state -> f action -> f action
dispatch this action = action >>= liftEff <<< runFn2 dispatch_ this

createElement :: forall props action state'. Store action state' -> ReduxReactClass state' props -> React.ReactElement
createElement store reduxClass =
React.createElement providerClass { store: store } [ reduxEl ]
where
reduxEl :: React.ReactElement
reduxEl = React.createElement (unsafeCoerce reduxClass) (unsafeCoerce unit) []

createStore :: forall eff action state. Reducer action state -> state -> Eff (Effects eff) (Store action state)
createStore = runFn2 createStore_

reducerOptic :: forall state state' action action'. LensP state state' -> PrismP action action' -> Reducer action' state' -> Reducer action state
reducerOptic lens prism k action state = either (const state) (\a -> set lens (k a state') state) action'
where
state' :: state'
state' = view lens state

action' :: Either action action'
action' = matching prism action

foreign import data REDUX :: !

foreign import data Store :: * -> * -> *

foreign import data ReduxReactClass :: * -> * -> *

foreign import connect :: forall state' props. (state' -> props) -> React.ReactClass props -> ReduxReactClass state' props

foreign import dispatch_ :: forall eff props action state. Fn2 (React.ReactThis props state) action (Eff (Effects eff) action)

foreign import providerClass :: forall action state'. React.ReactClass { store :: Store action state' }

foreign import createStore_ :: forall eff action state. Fn2 (Reducer action state) state (Eff (Effects eff) (Store action state))