Skip to content

Add setup function, to wrap componentDidMount #10

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 11 commits into from
Feb 21, 2018
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
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_