Skip to content

Commit dbbf740

Browse files
Marcin Szamotulskiethul
Marcin Szamotulski
authored andcommitted
React 16 (#109)
* React-16: polymorphic Render type * stateless components * Added ReactRender String instance. * ReactRender: int & number Also add `React.DOM.int` and `React.DOM.number` functions. * Added ComponentDidCatch * displayName of stateless components
1 parent 356ba14 commit dbbf740

File tree

5 files changed

+98
-24
lines changed

5 files changed

+98
-24
lines changed

bower.json

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
"purescript-eff": "^3.0.0",
2121
"purescript-prelude": "^3.0.0",
2222
"purescript-unsafe-coerce": "^3.0.0",
23+
"purescript-exceptions": "^3.1.0",
2324
"purescript-maybe": "^3.0.0",
2425
"purescript-nullable": "^3.0.0"
2526
},

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "purescript-react",
33
"files": [],
44
"peerDependencies": {
5-
"react": "^15.6.1",
5+
"react": "^16.0.0-alpha.13",
66
"create-react-class": "^15.6.0"
77
}
88
}

src/React.js

+22-2
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,9 @@ function transformState(this_){
108108
}
109109
exports.transformState = transformState;
110110

111-
function createClass(spec) {
111+
function createClass(toNullable, spec) {
112+
var didCatch = toNullable(spec.componentDidCatch)
113+
112114
var result = {
113115
displayName: spec.displayName,
114116
render: function(){
@@ -125,6 +127,9 @@ function createClass(spec) {
125127
componentDidMount: function(){
126128
return spec.componentDidMount(this)();
127129
},
130+
componentDidCatch: didCatch
131+
? function(error, info) {return didCatch(this)(error)(info)(); }
132+
: undefined,
128133
componentWillReceiveProps: function(nextProps){
129134
return spec.componentWillReceiveProps(this)(nextProps)();
130135
},
@@ -144,7 +149,22 @@ function createClass(spec) {
144149

145150
return createReactClass(result);
146151
}
147-
exports.createClass = createClass;
152+
exports["createClass'"] = createClass;
153+
154+
function capitalize(s) {
155+
if (!s)
156+
return s;
157+
return s.charAt(0).toUpperCase() + s.slice(1);
158+
};
159+
160+
function createClassStateless(dict) {
161+
return function (f) {
162+
if (!f.displayName)
163+
f.displayName = capitalize(f.name);
164+
return f;
165+
};
166+
};
167+
exports.createClassStateless = createClassStateless;
148168

149169
function forceUpdateCbImpl(this_, cb) {
150170
this_.forceUpdate(function() {

src/React.purs

+68-21
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
-- | This module defines foreign types and functions which wrap React's functionality.
22

33
module React
4-
( ReactElement
4+
( class ReactRender
5+
, ReactElement
56
, ReactComponent
67
, ReactThis
78
, TagName
@@ -25,6 +26,7 @@ module React
2526
, GetInitialState
2627
, ComponentWillMount
2728
, ComponentDidMount
29+
, ComponentDidCatch
2830
, ComponentWillReceiveProps
2931
, ShouldComponentUpdate
3032
, ComponentWillUpdate
@@ -76,8 +78,10 @@ module React
7678
import Prelude
7779

7880
import Control.Monad.Eff (kind Effect, Eff)
79-
import Data.Maybe (Maybe)
80-
import Data.Nullable (Nullable, toMaybe)
81+
import Control.Monad.Eff.Exception (Error)
82+
import Data.Function.Uncurried (Fn2, runFn2)
83+
import Data.Maybe (Maybe(Nothing))
84+
import Data.Nullable (Nullable, toMaybe, toNullable)
8185
import Control.Monad.Eff.Uncurried (EffFn2, runEffFn2)
8286
import Unsafe.Coerce (unsafeCoerce)
8387

@@ -160,15 +164,27 @@ type EventHandlerContext eff props state result =
160164
| eff
161165
) result
162166

167+
class ReactRender a
168+
169+
instance arrayReactRender :: ReactRender (Array ReactElement)
170+
171+
instance reactElementReactRender :: ReactRender ReactElement
172+
173+
instance stringReactRender :: ReactRender String
174+
175+
instance intReactRender :: ReactRender Int
176+
177+
instance numberReactRender :: ReactRender Number
178+
163179
-- | A render function.
164-
type Render props state eff =
180+
type Render props state render eff =
165181
ReactThis props state ->
166182
Eff
167183
( props :: ReactProps
168184
, refs :: ReactRefs Disallowed
169185
, state :: ReactState ReadOnly
170186
| eff
171-
) ReactElement
187+
) render
172188

173189
-- | A get initial state function.
174190
type GetInitialState props state eff =
@@ -200,6 +216,18 @@ type ComponentDidMount props state eff =
200216
| eff
201217
) Unit
202218

219+
type ComponentDidCatch props state eff =
220+
ReactThis props state ->
221+
Error ->
222+
{ componentStack :: String } ->
223+
Eff
224+
( props :: ReactProps
225+
, state :: ReactState ReadWrite
226+
, refs :: ReactRefs ReadOnly
227+
| eff
228+
) Unit
229+
230+
203231
-- | A component will receive props function.
204232
type ComponentWillReceiveProps props state eff =
205233
ReactThis props state ->
@@ -258,12 +286,13 @@ type ComponentWillUnmount props state eff =
258286
) Unit
259287

260288
-- | A specification of a component.
261-
type ReactSpec props state eff =
262-
{ render :: Render props state eff
289+
type ReactSpec props state render eff =
290+
{ render :: Render props state render eff
263291
, displayName :: String
264292
, getInitialState :: GetInitialState props state eff
265293
, componentWillMount :: ComponentWillMount props state eff
266294
, componentDidMount :: ComponentDidMount props state eff
295+
, componentDidCatch :: Maybe (ComponentDidCatch props state eff)
267296
, componentWillReceiveProps :: ComponentWillReceiveProps props state eff
268297
, shouldComponentUpdate :: ShouldComponentUpdate props state eff
269298
, componentWillUpdate :: ComponentWillUpdate props state eff
@@ -272,21 +301,24 @@ type ReactSpec props state eff =
272301
}
273302

274303
-- | Create a component specification with a provided state.
275-
spec :: forall props state eff.
276-
state -> Render props state eff -> ReactSpec props state eff
304+
spec :: forall props state render eff.
305+
ReactRender render =>
306+
state -> Render props state render eff -> ReactSpec props state render eff
277307
spec state = spec' \_ -> pure state
278308

279309
-- | Create a component specification with a get initial state function.
280-
spec' :: forall props state eff.
310+
spec' :: forall props state render eff.
311+
ReactRender render =>
281312
GetInitialState props state eff ->
282-
Render props state eff ->
283-
ReactSpec props state eff
313+
Render props state render eff ->
314+
ReactSpec props state render eff
284315
spec' getInitialState renderFn =
285316
{ render: renderFn
286317
, displayName: ""
287318
, getInitialState: getInitialState
288319
, componentWillMount: \_ -> pure unit
289320
, componentDidMount: \_ -> pure unit
321+
, componentDidCatch: Nothing
290322
, componentWillReceiveProps: \_ _ -> pure unit
291323
, shouldComponentUpdate: \_ _ _ -> pure true
292324
, componentWillUpdate: \_ _ _ -> pure unit
@@ -357,17 +389,32 @@ foreign import transformState :: forall props state eff.
357389
Eff (state :: ReactState ReadWrite | eff) Unit
358390

359391
-- | Create a React class from a specification.
360-
foreign import createClass :: forall props state eff.
361-
ReactSpec props state eff -> ReactClass props
362-
363-
-- | Create a stateless React class.
364-
createClassStateless :: forall props.
365-
(props -> ReactElement) -> ReactClass props
366-
createClassStateless = unsafeCoerce
392+
foreign import createClass' :: forall props state render eff.
393+
Fn2
394+
(forall a. Maybe a -> Nullable a)
395+
(ReactSpec props state render eff)
396+
(ReactClass props)
397+
398+
createClass :: forall props state render eff.
399+
ReactSpec props state render eff -> ReactClass props
400+
createClass spc = runFn2 createClass' toNullable spc
401+
402+
-- | Create a stateless React class. When using a non anonymous function the
403+
-- | displayName will be the capitalized name of the function, e.g.
404+
-- | ``` purescript
405+
-- | helloWorld = createClassStatelesss hellowWorldCls
406+
-- | where
407+
-- | hellowWorldCls props = ...
408+
-- | ```
409+
-- | Then the `displayName` will be set up to `HellowWorldCls`
410+
foreign import createClassStateless :: forall props render.
411+
ReactRender render =>
412+
(props -> render) -> ReactClass props
367413

368414
-- | Create a stateless React class with children access.
369-
createClassStateless' :: forall props.
370-
(props -> Array ReactElement -> ReactElement) -> ReactClass props
415+
createClassStateless' :: forall props render.
416+
ReactRender render =>
417+
(props -> Array ReactElement -> render) -> ReactClass props
371418
createClassStateless' k =
372419
createClassStateless \props ->
373420
k props (childrenToArray (unsafeCoerce props).children)

src/React/DOM.purs

+6
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ mkDOM dynamic tag props = createElement tag (unsafeFromPropsArray props)
1919
text :: String -> ReactElement
2020
text = unsafeCoerce
2121

22+
int :: Int -> ReactElement
23+
int = unsafeCoerce
24+
25+
number :: Number -> ReactElement
26+
number = unsafeCoerce
27+
2228
a :: Array Props -> Array ReactElement -> ReactElement
2329
a = mkDOM (IsDynamic false) "a"
2430

0 commit comments

Comments
 (0)