Skip to content

Commit c03129a

Browse files
natefaubionethul
authored andcommitted
Alternative class construction (#129)
* Alternative class construction This removes `createClass` and `spec` as well as the dependency on `create-react-class` in favor of `component` and `pureComponent` which creates constructors that inherit from `React.Component` and `React.PureComponent` in an idiomatic way for React. This also obviates the need for some machinery like `ref` handling, which can be implemented with `purescript-refs` instead. * Revert Ref -> Foreign * Move prop constraints to createElement * Add ref as a reserved prop * Add statelessComponent
1 parent 14b4c22 commit c03129a

File tree

5 files changed

+210
-313
lines changed

5 files changed

+210
-313
lines changed

bower.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
"purescript-unsafe-coerce": "^3.0.0",
2323
"purescript-exceptions": "^3.1.0",
2424
"purescript-maybe": "^3.0.0",
25-
"purescript-nullable": "^3.0.0"
25+
"purescript-nullable": "^3.0.0",
26+
"purescript-typelevel-prelude": "^2.5.0"
2627
},
2728
"devDependencies": {
2829
"purescript-console": "^3.0.0",

package.json

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22
"name": "purescript-react",
33
"files": [],
44
"peerDependencies": {
5-
"react": "^16.0.0",
6-
"create-react-class": "^15.6.0"
5+
"react": "^16.0.0"
76
}
87
}

src/React.js

+63-118
Original file line numberDiff line numberDiff line change
@@ -2,71 +2,74 @@
22
"use strict";
33

44
var React = require("react");
5-
var createReactClass = require("create-react-class");
65

7-
function getProps(this_) {
8-
return function(){
9-
return this_.props;
10-
};
11-
}
12-
exports.getProps = getProps;
6+
function createClass(baseClass) {
7+
function bindProperty(instance, prop, value) {
8+
switch (prop) {
9+
case 'componentDidMount':
10+
case 'componentDidUpdate':
11+
case 'componentWillMount':
12+
case 'componentWillUnmount':
13+
case 'render':
14+
case 'state':
15+
instance[prop] = value;
16+
break;
17+
18+
case 'componentWillReceiveProps':
19+
instance[prop] = function (a) { return value(a)(); };
20+
break;
21+
22+
case 'componentDidCatch':
23+
case 'componentWillUpdate':
24+
case 'shouldComponentUpdate':
25+
instance[prop] = function (a, b) { return value(a)(b)(); };
26+
break;
27+
28+
default:
29+
throw new Error('Not a component property: ' + prop);
30+
}
31+
}
1332

14-
function getRefs(this_) {
15-
return function(){
16-
return this_.refs;
33+
return function (displayName) {
34+
return function (ctrFn) {
35+
var Constructor = function (props) {
36+
baseClass.call(this, props);
37+
var spec = ctrFn(this)();
38+
for (var k in spec) {
39+
bindProperty(this, k, spec[k]);
40+
}
41+
};
42+
43+
Constructor.displayName = displayName;
44+
Constructor.prototype = Object.create(baseClass.prototype);
45+
Constructor.prototype.constructor = Constructor;
46+
47+
return Constructor;
48+
};
1749
};
1850
}
19-
exports.getRefs = getRefs;
2051

21-
function childrenToArray(children) {
22-
var result = [];
52+
exports.componentImpl = createClass(React.Component);
2353

24-
React.Children.forEach(children, function(child){
25-
result.push(child);
26-
});
54+
exports.pureComponentImpl = createClass(React.PureComponent);
2755

28-
return result;
29-
}
30-
exports.childrenToArray = childrenToArray;
56+
exports.statelessComponent = function(x) { return x; };
3157

32-
function getChildren(this_) {
58+
function getProps(this_) {
3359
return function(){
34-
var children = this_.props.children;
35-
36-
var result = childrenToArray(children);
37-
38-
return result;
60+
return this_.props;
3961
};
4062
}
41-
exports.getChildren = getChildren;
63+
exports.getProps = getProps;
4264

43-
function readRefImpl (this_) {
44-
return function(name) {
45-
return function() {
46-
return this_[name];
47-
}
48-
}
49-
}
50-
exports.readRefImpl = readRefImpl;
65+
exports.childrenToArray = React.Children.toArray
5166

52-
function writeRef(this_) {
53-
return function(name) {
54-
return function(node) {
55-
return function() {
56-
this_[name] = node;
57-
return {};
58-
}
59-
}
60-
}
61-
}
62-
exports.writeRef = writeRef;
67+
exports.childrenCount = React.Children.count;
6368

6469
function writeState(this_) {
6570
return function(state){
6671
return function(){
67-
this_.setState({
68-
state: state
69-
});
72+
this_.setState(state);
7073
return state;
7174
};
7275
};
@@ -77,9 +80,7 @@ function writeStateWithCallback(this_, cb) {
7780
return function(state){
7881
return function(cb){
7982
return function() {
80-
this_.setState({
81-
state: state
82-
}, cb);
83+
this_.setState(state, cb);
8384
return state;
8485
};
8586
};
@@ -89,7 +90,7 @@ exports.writeStateWithCallback = writeStateWithCallback;
8990

9091
function readState(this_) {
9192
return function(){
92-
return this_.state.state;
93+
return this_.state;
9394
};
9495
}
9596
exports.readState = readState;
@@ -98,71 +99,13 @@ function transformState(this_){
9899
return function(update){
99100
return function(){
100101
this_.setState(function(old, props){
101-
return {state: update(old.state)};
102+
return update(old);
102103
});
103104
};
104105
};
105106
}
106107
exports.transformState = transformState;
107108

108-
function createClass(toNullable, spec) {
109-
var didCatch = toNullable(spec.componentDidCatch)
110-
111-
var result = {
112-
displayName: spec.displayName,
113-
render: function(){
114-
return spec.render(this)();
115-
},
116-
getInitialState: function(){
117-
return {
118-
state: spec.getInitialState(this)()
119-
};
120-
},
121-
componentWillMount: function(){
122-
return spec.componentWillMount(this)();
123-
},
124-
componentDidMount: function(){
125-
return spec.componentDidMount(this)();
126-
},
127-
componentDidCatch: didCatch
128-
? function(error, info) {return didCatch(this)(error)(info)(); }
129-
: undefined,
130-
componentWillReceiveProps: function(nextProps){
131-
return spec.componentWillReceiveProps(this)(nextProps)();
132-
},
133-
shouldComponentUpdate: function(nextProps, nextState){
134-
return spec.shouldComponentUpdate(this)(nextProps)(nextState.state)();
135-
},
136-
componentWillUpdate: function(nextProps, nextState){
137-
return spec.componentWillUpdate(this)(nextProps)(nextState.state)();
138-
},
139-
componentDidUpdate: function(prevProps, prevState){
140-
return spec.componentDidUpdate(this)(prevProps)(prevState.state)();
141-
},
142-
componentWillUnmount: function(){
143-
return spec.componentWillUnmount(this)();
144-
}
145-
};
146-
147-
return createReactClass(result);
148-
}
149-
exports["createClass'"] = createClass;
150-
151-
function capitalize(s) {
152-
if (!s)
153-
return s;
154-
return s.charAt(0).toUpperCase() + s.slice(1);
155-
};
156-
157-
function createClassStateless(dict) {
158-
return function (f) {
159-
if (!f.displayName)
160-
f.displayName = capitalize(f.name);
161-
return f;
162-
};
163-
};
164-
exports.createClassStateless = createClassStateless;
165-
166109
function forceUpdateCbImpl(this_, cb) {
167110
this_.forceUpdate(function() {
168111
return cb();
@@ -185,24 +128,26 @@ function createElement(class_) {
185128
};
186129
};
187130
}
188-
exports.createElement = createElement;
131+
exports.createElementImpl = createElement;
189132
exports.createElementTagName = createElement;
190133

134+
function createLeafElement(class_) {
135+
return function(props) {
136+
return React.createElement(class_, props);
137+
};
138+
}
139+
exports.createLeafElementImpl = createLeafElement;
140+
191141
function createElementDynamic(class_) {
192142
return function(props) {
193143
return function(children){
194144
return React.createElement(class_, props, children);
195145
};
196146
};
197147
};
198-
exports.createElementDynamic = createElementDynamic;
148+
exports.createElementDynamicImpl = createElementDynamic;
199149
exports.createElementTagNameDynamic = createElementDynamic;
200150

201-
function createFactory(class_) {
202-
return React.createFactory(class_);
203-
}
204-
exports.createFactory = createFactory;
205-
206151
function preventDefault(event) {
207152
return function() {
208153
event.preventDefault();

0 commit comments

Comments
 (0)