Skip to content

Commit d40597c

Browse files
authored
Add setup function, to wrap componentDidMount (#10)
* 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
1 parent 833a86d commit d40597c

19 files changed

+242
-12
lines changed

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

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

5-
## Features
5+
## Features
66

77
- All React DOM elements and attributes are supported.
88
- An intuitive API for specifying props - no arrays of key value pairs, just records.
@@ -41,7 +41,8 @@ type ExampleState =
4141
-- state update callback, and produces a document.
4242
example :: R.ReactComponent ExampleProps
4343
example = R.react
44-
{ initialState: \_ -> { counter: 0 }
44+
{ initialState: { counter: 0 }
45+
, receiveProps: \_ _ _ -> pure unit
4546
, render: \{ label } { counter } setState ->
4647
R.button { onClick: mkEffFn1 \_ -> do
4748
setState { counter: counter + 1 }

examples/component/.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
output
2+
html/index.js
3+
package-lock.json
4+
node_modules

examples/component/Makefile

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
all:
2+
purs compile src/*.purs '../../src/**/*.purs' '../../bower_components/purescript-*/src/**/*.purs'
3+
purs bundle --module Container output/*/*.js > output/bundle.js
4+
echo 'module.exports = PS.Container;' >> output/bundle.js
5+
node_modules/browserify/bin/cmd.js output/bundle.js index.js -o html/index.js

examples/component/README.md

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Component Example
2+
3+
## Building
4+
5+
```
6+
npm install
7+
make all
8+
```
9+
10+
This will compile the PureScript source files, bundle them, and use Browserify to combine PureScript and NPM sources into a single bundle.
11+
12+
Then open `html/index.html` in your browser.

examples/component/html/index.html

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>react-basic example</title>
5+
</head>
6+
<body>
7+
<div id="container"></div>
8+
<script src="index.js"></script>
9+
</body>
10+
</html>

examples/component/index.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"use strict";
2+
3+
var React = require("react");
4+
var ReactDOM = require("react-dom");
5+
var Container = require("./output/bundle.js");
6+
7+
ReactDOM.render(
8+
React.createElement(Container.component, { label: 'Increment' }),
9+
document.getElementById("container")
10+
);

examples/component/package.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "component",
3+
"version": "1.0.0",
4+
"description": "",
5+
"keywords": [],
6+
"author": "",
7+
"dependencies": {
8+
"create-react-class": "^15.6.2",
9+
"react": "^15.6.2",
10+
"react-dom": "^15.6.2"
11+
},
12+
"devDependencies": {
13+
"browserify": "^16.1.0"
14+
}
15+
}

examples/component/src/Container.purs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
module Container where
2+
3+
import Prelude
4+
5+
import React.Basic as R
6+
import ToggleButton as ToggleButton
7+
8+
component :: R.ReactComponent Unit
9+
component = R.react
10+
{ initialState: unit
11+
, receiveProps: \_ _ _ -> pure unit
12+
, render: \_ _ setState ->
13+
R.div { } [ R.component ToggleButton.component { on: true }
14+
, R.component ToggleButton.component { on: false }
15+
]
16+
}
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
module ToggleButton where
2+
3+
import Prelude
4+
5+
import Control.Monad.Eff.Uncurried (mkEffFn1)
6+
import React.Basic as R
7+
8+
type ExampleProps =
9+
{ on :: Boolean
10+
}
11+
12+
type ExampleState =
13+
{ on :: Boolean
14+
}
15+
16+
component :: R.ReactComponent ExampleProps
17+
component = R.react
18+
{ initialState: { on: false }
19+
, receiveProps: \{ on } _ setState -> setState { on }
20+
, render: \_ { on } setState ->
21+
R.button { onClick: mkEffFn1 \_ -> setState { on: not on }
22+
}
23+
[ R.text if on then "On" else "Off" ]
24+
}

examples/counter/.gitignore

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
output
2+
html/index.js
3+
package-lock.json
4+
node_modules

examples/counter/Makefile

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
all:
2+
purs compile src/*.purs '../../src/**/*.purs' '../../bower_components/purescript-*/src/**/*.purs'
3+
purs bundle --module Counter output/*/*.js > output/bundle.js
4+
echo 'module.exports = PS.Counter;' >> output/bundle.js
5+
node_modules/browserify/bin/cmd.js output/bundle.js index.js -o html/index.js

examples/counter/README.md

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
# Counter Example
2+
3+
## Building
4+
5+
```
6+
npm install
7+
make all
8+
```
9+
10+
This will compile the PureScript source files, bundle them, and use Browserify to combine PureScript and NPM sources into a single bundle.
11+
12+
Then open `html/index.html` in your browser.

examples/counter/html/index.html

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<title>react-basic example</title>
5+
</head>
6+
<body>
7+
<div id="container"></div>
8+
<script src="index.js"></script>
9+
</body>
10+
</html>

examples/counter/index.js

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
"use strict";
2+
3+
var React = require("react");
4+
var ReactDOM = require("react-dom");
5+
var Counter = require("./output/bundle.js");
6+
7+
ReactDOM.render(
8+
React.createElement(Counter.component, { label: 'Increment' }),
9+
document.getElementById("container")
10+
);

examples/counter/package.json

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
{
2+
"name": "counter",
3+
"version": "1.0.0",
4+
"description": "",
5+
"keywords": [],
6+
"author": "",
7+
"dependencies": {
8+
"create-react-class": "^15.6.2",
9+
"react": "^15.6.2",
10+
"react-dom": "^15.6.2"
11+
},
12+
"devDependencies": {
13+
"browserify": "^16.1.0"
14+
}
15+
}

examples/counter/src/Counter.purs

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
module Counter where
2+
3+
import Prelude
4+
5+
import Control.Monad.Eff.Uncurried (mkEffFn1)
6+
import React.Basic as R
7+
8+
-- The props for the component
9+
type ExampleProps =
10+
{ label :: String
11+
}
12+
13+
-- The internal state of the component
14+
type ExampleState =
15+
{ counter :: Int
16+
}
17+
18+
-- Create a component by passing a record to the `react` function.
19+
-- The `render` function takes the props and current state, as well as a
20+
-- state update callback, and produces a document.
21+
component :: R.ReactComponent ExampleProps
22+
component = R.react
23+
{ initialState: { counter: 0 }
24+
, receiveProps: \_ _ _ -> pure unit
25+
, render: \{ label } { counter } setState ->
26+
R.button { onClick: mkEffFn1 \_ -> do
27+
setState { counter: counter + 1 }
28+
}
29+
[ R.text (label <> ": " <> show counter) ]
30+
}

generated-docs/React/Basic.md

+11-3
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,27 @@
33
#### `react`
44

55
``` purescript
6-
react :: forall props state. { initialState :: state, render :: props -> state -> (state -> Eff (react :: ReactFX) Unit) -> JSX } -> ReactComponent props
6+
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
77
```
88

99
Create a React component from a _specification_ of that component.
1010

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

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

19+
#### `component`
20+
21+
``` purescript
22+
component :: forall props. ReactComponent props -> props -> JSX
23+
```
24+
25+
Create a `JSX` node from another React component, by providing the props.
26+
1927

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

src/React/Basic.js

+21-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,23 @@ var React = require('react');
55
exports.react_ = function(spec) {
66
return React.createClass({
77
getInitialState: function() {
8-
return spec.initialState(this.props);
8+
return spec.initialState;
9+
},
10+
componentDidMount: function() {
11+
var this_ = this;
12+
spec.receiveProps(this.props, this.state, function(newState) {
13+
return function() {
14+
this_.setState(newState);
15+
};
16+
});
17+
},
18+
componentWillReceiveProps: function(newProps) {
19+
var this_ = this;
20+
spec.receiveProps(newProps, this.state, function(newState) {
21+
return function() {
22+
this_.setState(newState);
23+
};
24+
});
925
},
1026
render: function() {
1127
var this_ = this;
@@ -17,3 +33,7 @@ exports.react_ = function(spec) {
1733
}
1834
});
1935
};
36+
37+
exports.component_ = function(component, props) {
38+
return React.createElement(component, props);
39+
}

src/React/Basic.purs

+25-6
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,56 @@
11
module React.Basic
22
( react
3+
, component
34
, module React.Basic.DOM
45
, module React.Basic.Types
56
) where
67

78
import Prelude
89

910
import Control.Monad.Eff (Eff, kind Effect)
10-
import Data.Function.Uncurried (Fn3, mkFn3)
11+
import Control.Monad.Eff.Uncurried (EffFn3, mkEffFn3)
12+
import Data.Function.Uncurried (Fn2, runFn2, Fn3, mkFn3)
1113
import React.Basic.DOM as React.Basic.DOM
1214
import React.Basic.Types (CSS, EventHandler, JSX, ReactComponent, ReactFX)
1315
import React.Basic.Types as React.Basic.Types
1416

1517
foreign import react_
1618
:: forall props state
17-
. { initialState :: props -> state
19+
. { initialState :: state
20+
, receiveProps :: EffFn3 (react :: ReactFX) props state (state -> Eff (react :: ReactFX) Unit) Unit
1821
, render :: Fn3 props state (state -> Eff (react :: ReactFX) Unit) JSX
1922
}
2023
-> ReactComponent props
2124

2225
-- | Create a React component from a _specification_ of that component.
2326
-- |
2427
-- | A _specification_ consists of a state type, an initial value for that state,
25-
-- | and a rendering function which takes a value of that state type, additional
26-
-- | _props_ (which will be passed in by the user) and a state update function.
28+
-- | a function to apply incoming props to the internal state, and a rendering
29+
-- | function which takes props, state and a state update function.
2730
-- |
2831
-- | The rendering function should return a value of type `JSX`, which can be
2932
-- | constructed using the helper functions provided by the `React.Basic.DOM`
3033
-- | module (and re-exported here).
3134
react
3235
:: forall props state
33-
. { initialState :: props -> state
36+
. { initialState :: state
37+
, receiveProps :: props -> state -> (state -> Eff (react :: ReactFX) Unit) -> Eff (react :: ReactFX) Unit
3438
, render :: props -> state -> (state -> Eff (react :: ReactFX) Unit) -> JSX
3539
}
3640
-> ReactComponent props
37-
react { initialState, render } = react_ { initialState, render: mkFn3 render }
41+
react { initialState, receiveProps, render } =
42+
react_
43+
{ initialState
44+
, receiveProps: mkEffFn3 receiveProps
45+
, render: mkFn3 render
46+
}
47+
48+
foreign import component_ :: forall props. Fn2 (ReactComponent props) props JSX
49+
50+
-- | Create a `JSX` node from another React component, by providing the props.
51+
component
52+
:: forall props
53+
. ReactComponent props
54+
-> props
55+
-> JSX
56+
component = runFn2 component_

0 commit comments

Comments
 (0)