Skip to content

Commit 704efe9

Browse files
author
Michael Trotter
committed
Split the spec component type from ReactComponent; fix toReactComponent
1 parent 5161ed1 commit 704efe9

3 files changed

Lines changed: 71 additions & 40 deletions

File tree

src/React/Basic.js

Lines changed: 54 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -7,39 +7,47 @@ exports.createComponent_ = function(noUpdate, buildStateUpdate, displayName) {
77
function contextToSelf(instance) {
88
var self = {
99
props: instance.props.$$props,
10-
state: instance.state === undefined ? undefined : instance.state.$$state,
10+
state: instance.state === null ? null : instance.state.$$state,
1111
readProps: function() {
1212
return self.instance_.props.$$props;
1313
},
1414
readState: function() {
1515
var state = self.instance_.state;
16-
return state === undefined ? undefined : state.$$state;
16+
return state === null ? null : state.$$state;
1717
},
1818
send: function(action) {
1919
return function() {
20-
var updates = buildStateUpdate(
21-
self.instance_.$$spec.update(self)(action)
20+
var sideEffects = null;
21+
self.instance_.setState(
22+
function(s) {
23+
var setStateContext = contextToSelf(self.instance_);
24+
setStateContext.state = s.$$state;
25+
var updates = buildStateUpdate(
26+
self.instance_.$$spec.update(setStateContext)(action)
27+
);
28+
if (updates.effects !== null) {
29+
sideEffects = updates.effects;
30+
}
31+
if (updates.state !== null && updates.state !== s.$$state) {
32+
return { $$state: updates.state };
33+
} else {
34+
return null;
35+
}
36+
},
37+
function() {
38+
if (sideEffects !== null) {
39+
sideEffects(contextToSelf(this))();
40+
}
41+
}
2242
);
23-
if (updates.state !== null) {
24-
self.instance_.setState(
25-
{ $$state: updates.state },
26-
updates.effects !== null
27-
? function() {
28-
updates.effects(contextToSelf(this))();
29-
}
30-
: undefined
31-
);
32-
} else if (updates.effects !== null) {
33-
updates.effects(self)();
34-
}
3543
};
3644
},
3745
instance_: instance
3846
};
3947
return self;
4048
}
4149

42-
var defaultInitialState = {};
50+
var defaultInitialState = null;
4351
var defaultShouldUpdate = function() {
4452
return function() {
4553
return function() {
@@ -69,10 +77,10 @@ exports.createComponent_ = function(noUpdate, buildStateUpdate, displayName) {
6977
this.$$spec = props.$$spec;
7078
this.state =
7179
// React may optimize components with no state,
72-
// so we leave state undefined if it was left as
80+
// so we leave state null if it was left as
7381
// the default value.
7482
this.$$spec.initialState === defaultInitialState
75-
? undefined
83+
? null
7684
: { $$state: this.$$spec.initialState };
7785
return this;
7886
};
@@ -117,12 +125,12 @@ exports.createStatelessComponent = function(displayName) {
117125
function contextToSelf(instance) {
118126
var self = {
119127
props: instance.props.$$props,
120-
state: undefined,
128+
state: null,
121129
readProps: function() {
122130
return self.instance_.props.$$props;
123131
},
124132
readState: function() {
125-
return undefined;
133+
return null;
126134
},
127135
send: function() {
128136
return function() {};
@@ -132,7 +140,7 @@ exports.createStatelessComponent = function(displayName) {
132140
return self;
133141
}
134142

135-
var defaultInitialState = {};
143+
var defaultInitialState = null;
136144
var defaultShouldUpdate = function() {
137145
return function() {
138146
return function() {
@@ -183,16 +191,36 @@ exports.createStatelessComponent = function(displayName) {
183191
};
184192
};
185193

186-
exports.make = function(component) {
194+
exports.make = function($$spec) {
187195
return function($$props) {
188196
var props = {
189197
$$props: $$props,
190-
$$spec: component
198+
$$spec: $$spec
191199
};
192-
return React.createElement(component.$$type, props);
200+
return React.createElement($$spec.$$type, props);
193201
};
194202
};
195203

204+
exports.toReactComponent = function($$spec) {
205+
var Component = function constructor() {
206+
return this;
207+
};
208+
209+
Component.prototype = Object.create(React.Component.prototype);
210+
211+
Component.displayName = $$spec.$$type.displayName + " (Wrapper)";
212+
213+
Component.prototype.render = function() {
214+
var props = {
215+
$$props: this.props,
216+
$$spec: $$spec
217+
};
218+
return React.createElement($$spec.$$type, props);
219+
};
220+
221+
return Component;
222+
};
223+
196224
exports.keyed_ = function(key, child) {
197225
return React.createElement(Fragment, { key: key }, child);
198226
};
@@ -204,9 +232,7 @@ exports.element_ = function(component, props) {
204232
);
205233
};
206234

207-
exports.elementKeyed_ = function(key, child) {
208-
return React.createElement.call(null, Fragment, { key: key }, child);
209-
};
235+
exports.elementKeyed_ = exports.element_;
210236

211237
exports.fragment = function(children) {
212238
return React.createElement.apply(null, [Fragment, {}].concat(children));

src/React/Basic.purs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ module React.Basic
22
( Component
33
, StatelessComponent
44
, ComponentSpec
5+
, ComponentType
56
, JSX
67
, Update
78
, StateUpdate(..)
@@ -42,8 +43,10 @@ instance semigroupJSX :: Semigroup JSX where
4243
instance monoidJSX :: Monoid JSX where
4344
mempty = empty
4445

46+
data ComponentType props state action
47+
4548
type ComponentSpec props state action =
46-
{ "$$type" :: ReactComponent props
49+
{ "$$type" :: ComponentType props state action
4750
, initialState :: state
4851
, shouldUpdate :: LimitedSelf props state -> props -> state -> Boolean
4952
, didMount :: Self props state action -> Effect Unit
@@ -187,7 +190,7 @@ data ReactComponentInstance
187190

188191
createComponent
189192
:: String
190-
-> { "$$type" :: forall props. ReactComponent props
193+
-> { "$$type" :: forall props state action. ComponentType props state action
191194
, initialState :: forall state. state
192195
, shouldUpdate :: forall props state. LimitedSelf props state -> props -> state -> Boolean
193196
, didMount :: forall props state action. Self props state action -> Effect Unit
@@ -206,7 +209,7 @@ foreign import createComponent_
206209
, effects :: Nullable (Self props state action -> Effect Unit)
207210
})
208211
String
209-
({ "$$type" :: forall props. ReactComponent props
212+
({ "$$type" :: forall props state action. ComponentType props state action
210213
, initialState :: forall state. state
211214
, shouldUpdate :: forall props state. LimitedSelf props state -> props -> state -> Boolean
212215
, didMount :: forall props state action. Self props state action -> Effect Unit
@@ -219,7 +222,7 @@ foreign import createComponent_
219222
-- | Creates a named, stateless component
220223
foreign import createStatelessComponent
221224
:: String
222-
-> { "$$type" :: forall props. ReactComponent props
225+
-> { "$$type" :: forall props state action. ComponentType props state action
223226
, initialState :: Void
224227
, shouldUpdate :: forall props. LimitedSelf props Void -> props -> Void -> Boolean
225228
, didMount :: forall props. Self props Void Void -> Effect Unit
@@ -270,5 +273,7 @@ foreign import element_ :: forall props. Fn2 (ReactComponent { | props }) { | pr
270273

271274
foreign import elementKeyed_ :: forall props. Fn2 (ReactComponent { | props }) { key :: String | props } JSX
272275

273-
toReactComponent :: forall props. ({ | props } -> JSX) -> ReactComponent { | props }
274-
toReactComponent = unsafeCoerce
276+
foreign import toReactComponent :: forall props state action. ComponentSpec { | props } state action -> ReactComponent { | props }
277+
278+
displayName :: forall props state action. ComponentSpec props state action -> String
279+
displayName = _.displayName <<< unsafeCoerce <<< _."$$type"

src/React/Basic/Compat.purs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,18 @@ component
2222
}
2323
-> ReactComponent { | props }
2424
component { displayName, initialState, receiveProps, render } =
25-
toReactComponent (make (createComponent displayName)
25+
toReactComponent (createComponent displayName)
2626
{ initialState = initialState
2727
, didMount = receiveProps <<< selfToLegacySelf
2828
, didUpdate = receiveProps <<< selfToLegacySelf
29-
, update = \self newState -> Update newState
29+
, update = \self stateUpdate -> Update (stateUpdate self.state)
3030
, render = render <<< selfToLegacySelf
31-
})
31+
}
3232
where
3333
selfToLegacySelf { props, state, send } =
3434
{ props
3535
, state
36-
, setState: \fn -> send (fn state)
36+
, setState: send
3737
}
3838

3939
-- | Supports a common subset of the v2 API to ease the upgrade process
@@ -44,6 +44,6 @@ stateless
4444
}
4545
-> ReactComponent { | props }
4646
stateless { displayName, render } =
47-
toReactComponent (make (createStatelessComponent displayName)
47+
toReactComponent (createStatelessComponent displayName)
4848
{ render = \self -> render self.props
49-
})
49+
}

0 commit comments

Comments
 (0)