Skip to content

Commit

Permalink
Add setup function, to wrap componentDidMount (#10)
Browse files Browse the repository at this point in the history
* Add setup function, to wrap componentDidMount

* Bind this_

* Counter example (no webpack)

* Update for new setup function

* Add component function, and example

* Rename to receiveProps, remove props from initialState

* Update readme

* Remove package-lock.json
  • Loading branch information
paf31 authored Feb 21, 2018
1 parent 833a86d commit d40597c
Show file tree
Hide file tree
Showing 19 changed files with 242 additions and 12 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

This package implements an opinionated set of bindings to the React library, optimizing for the most basic use cases.

## Features
## Features

- All React DOM elements and attributes are supported.
- An intuitive API for specifying props - no arrays of key value pairs, just records.
Expand Down Expand Up @@ -41,7 +41,8 @@ type ExampleState =
-- state update callback, and produces a document.
example :: R.ReactComponent ExampleProps
example = R.react
{ initialState: \_ -> { counter: 0 }
{ initialState: { counter: 0 }
, receiveProps: \_ _ _ -> pure unit
, render: \{ label } { counter } setState ->
R.button { onClick: mkEffFn1 \_ -> do
setState { counter: counter + 1 }
Expand Down
4 changes: 4 additions & 0 deletions examples/component/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output
html/index.js
package-lock.json
node_modules
5 changes: 5 additions & 0 deletions examples/component/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
all:
purs compile src/*.purs '../../src/**/*.purs' '../../bower_components/purescript-*/src/**/*.purs'
purs bundle --module Container output/*/*.js > output/bundle.js
echo 'module.exports = PS.Container;' >> output/bundle.js
node_modules/browserify/bin/cmd.js output/bundle.js index.js -o html/index.js
12 changes: 12 additions & 0 deletions examples/component/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Component Example

## Building

```
npm install
make all
```

This will compile the PureScript source files, bundle them, and use Browserify to combine PureScript and NPM sources into a single bundle.

Then open `html/index.html` in your browser.
10 changes: 10 additions & 0 deletions examples/component/html/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>react-basic example</title>
</head>
<body>
<div id="container"></div>
<script src="index.js"></script>
</body>
</html>
10 changes: 10 additions & 0 deletions examples/component/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"use strict";

var React = require("react");
var ReactDOM = require("react-dom");
var Container = require("./output/bundle.js");

ReactDOM.render(
React.createElement(Container.component, { label: 'Increment' }),
document.getElementById("container")
);
15 changes: 15 additions & 0 deletions examples/component/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "component",
"version": "1.0.0",
"description": "",
"keywords": [],
"author": "",
"dependencies": {
"create-react-class": "^15.6.2",
"react": "^15.6.2",
"react-dom": "^15.6.2"
},
"devDependencies": {
"browserify": "^16.1.0"
}
}
16 changes: 16 additions & 0 deletions examples/component/src/Container.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module Container where

import Prelude

import React.Basic as R
import ToggleButton as ToggleButton

component :: R.ReactComponent Unit
component = R.react
{ initialState: unit
, receiveProps: \_ _ _ -> pure unit
, render: \_ _ setState ->
R.div { } [ R.component ToggleButton.component { on: true }
, R.component ToggleButton.component { on: false }
]
}
24 changes: 24 additions & 0 deletions examples/component/src/ToggleButton.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
module ToggleButton where

import Prelude

import Control.Monad.Eff.Uncurried (mkEffFn1)
import React.Basic as R

type ExampleProps =
{ on :: Boolean
}

type ExampleState =
{ on :: Boolean
}

component :: R.ReactComponent ExampleProps
component = R.react
{ initialState: { on: false }
, receiveProps: \{ on } _ setState -> setState { on }
, render: \_ { on } setState ->
R.button { onClick: mkEffFn1 \_ -> setState { on: not on }
}
[ R.text if on then "On" else "Off" ]
}
4 changes: 4 additions & 0 deletions examples/counter/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
output
html/index.js
package-lock.json
node_modules
5 changes: 5 additions & 0 deletions examples/counter/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
all:
purs compile src/*.purs '../../src/**/*.purs' '../../bower_components/purescript-*/src/**/*.purs'
purs bundle --module Counter output/*/*.js > output/bundle.js
echo 'module.exports = PS.Counter;' >> output/bundle.js
node_modules/browserify/bin/cmd.js output/bundle.js index.js -o html/index.js
12 changes: 12 additions & 0 deletions examples/counter/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Counter Example

## Building

```
npm install
make all
```

This will compile the PureScript source files, bundle them, and use Browserify to combine PureScript and NPM sources into a single bundle.

Then open `html/index.html` in your browser.
10 changes: 10 additions & 0 deletions examples/counter/html/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
<!DOCTYPE html>
<html>
<head>
<title>react-basic example</title>
</head>
<body>
<div id="container"></div>
<script src="index.js"></script>
</body>
</html>
10 changes: 10 additions & 0 deletions examples/counter/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
"use strict";

var React = require("react");
var ReactDOM = require("react-dom");
var Counter = require("./output/bundle.js");

ReactDOM.render(
React.createElement(Counter.component, { label: 'Increment' }),
document.getElementById("container")
);
15 changes: 15 additions & 0 deletions examples/counter/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"name": "counter",
"version": "1.0.0",
"description": "",
"keywords": [],
"author": "",
"dependencies": {
"create-react-class": "^15.6.2",
"react": "^15.6.2",
"react-dom": "^15.6.2"
},
"devDependencies": {
"browserify": "^16.1.0"
}
}
30 changes: 30 additions & 0 deletions examples/counter/src/Counter.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
module Counter where

import Prelude

import Control.Monad.Eff.Uncurried (mkEffFn1)
import React.Basic as R

-- The props for the component
type ExampleProps =
{ label :: String
}

-- The internal state of the component
type ExampleState =
{ counter :: Int
}

-- Create a component by passing a record to the `react` function.
-- The `render` function takes the props and current state, as well as a
-- state update callback, and produces a document.
component :: R.ReactComponent ExampleProps
component = R.react
{ initialState: { counter: 0 }
, receiveProps: \_ _ _ -> pure unit
, render: \{ label } { counter } setState ->
R.button { onClick: mkEffFn1 \_ -> do
setState { counter: counter + 1 }
}
[ R.text (label <> ": " <> show counter) ]
}
14 changes: 11 additions & 3 deletions generated-docs/React/Basic.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,27 @@
#### `react`

``` purescript
react :: forall props state. { initialState :: state, render :: props -> state -> (state -> Eff (react :: ReactFX) Unit) -> JSX } -> ReactComponent props
react :: forall props state. { initialState :: state, receiveProps :: props -> state -> (state -> Eff (react :: ReactFX) Unit) -> Eff (react :: ReactFX) Unit, render :: props -> state -> (state -> Eff (react :: ReactFX) Unit) -> JSX } -> ReactComponent props
```

Create a React component from a _specification_ of that component.

A _specification_ consists of a state type, an initial value for that state,
and a rendering function which takes a value of that state type, additional
_props_ (which will be passed in by the user) and a state update function.
a function to apply incoming props to the internal state, and a rendering
function which takes props, state and a state update function.

The rendering function should return a value of type `JSX`, which can be
constructed using the helper functions provided by the `React.Basic.DOM`
module (and re-exported here).

#### `component`

``` purescript
component :: forall props. ReactComponent props -> props -> JSX
```

Create a `JSX` node from another React component, by providing the props.


### Re-exported from React.Basic.DOM:

Expand Down
22 changes: 21 additions & 1 deletion src/React/Basic.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,23 @@ var React = require('react');
exports.react_ = function(spec) {
return React.createClass({
getInitialState: function() {
return spec.initialState(this.props);
return spec.initialState;
},
componentDidMount: function() {
var this_ = this;
spec.receiveProps(this.props, this.state, function(newState) {
return function() {
this_.setState(newState);
};
});
},
componentWillReceiveProps: function(newProps) {
var this_ = this;
spec.receiveProps(newProps, this.state, function(newState) {
return function() {
this_.setState(newState);
};
});
},
render: function() {
var this_ = this;
Expand All @@ -17,3 +33,7 @@ exports.react_ = function(spec) {
}
});
};

exports.component_ = function(component, props) {
return React.createElement(component, props);
}
31 changes: 25 additions & 6 deletions src/React/Basic.purs
Original file line number Diff line number Diff line change
@@ -1,37 +1,56 @@
module React.Basic
( react
, component
, module React.Basic.DOM
, module React.Basic.Types
) where

import Prelude

import Control.Monad.Eff (Eff, kind Effect)
import Data.Function.Uncurried (Fn3, mkFn3)
import Control.Monad.Eff.Uncurried (EffFn3, mkEffFn3)
import Data.Function.Uncurried (Fn2, runFn2, Fn3, mkFn3)
import React.Basic.DOM as React.Basic.DOM
import React.Basic.Types (CSS, EventHandler, JSX, ReactComponent, ReactFX)
import React.Basic.Types as React.Basic.Types

foreign import react_
:: forall props state
. { initialState :: props -> state
. { initialState :: state
, receiveProps :: EffFn3 (react :: ReactFX) props state (state -> Eff (react :: ReactFX) Unit) Unit
, render :: Fn3 props state (state -> Eff (react :: ReactFX) Unit) JSX
}
-> ReactComponent props

-- | Create a React component from a _specification_ of that component.
-- |
-- | A _specification_ consists of a state type, an initial value for that state,
-- | and a rendering function which takes a value of that state type, additional
-- | _props_ (which will be passed in by the user) and a state update function.
-- | a function to apply incoming props to the internal state, and a rendering
-- | function which takes props, state and a state update function.
-- |
-- | The rendering function should return a value of type `JSX`, which can be
-- | constructed using the helper functions provided by the `React.Basic.DOM`
-- | module (and re-exported here).
react
:: forall props state
. { initialState :: props -> state
. { initialState :: state
, receiveProps :: props -> state -> (state -> Eff (react :: ReactFX) Unit) -> Eff (react :: ReactFX) Unit
, render :: props -> state -> (state -> Eff (react :: ReactFX) Unit) -> JSX
}
-> ReactComponent props
react { initialState, render } = react_ { initialState, render: mkFn3 render }
react { initialState, receiveProps, render } =
react_
{ initialState
, receiveProps: mkEffFn3 receiveProps
, render: mkFn3 render
}

foreign import component_ :: forall props. Fn2 (ReactComponent props) props JSX

-- | Create a `JSX` node from another React component, by providing the props.
component
:: forall props
. ReactComponent props
-> props
-> JSX
component = runFn2 component_

0 comments on commit d40597c

Please sign in to comment.