@@ -14,6 +14,12 @@ For a more high-level set of bindings, you might like to look at `purescript-the
1414bower install purescript-react
1515```
1616
17+ This library requires the ` react ` module. This dependency may be satisfied by installing the NPM [ react package] ( https://www.npmjs.com/package/react ) .
18+
19+ ```
20+ npm install react
21+ ```
22+
1723## Related Modules
1824
1925- [ React DOM] ( https://github.com/purescript-contrib/purescript-react-dom )
@@ -22,3 +28,189 @@ bower install purescript-react
2228## Example
2329
2430Please refer to [ purescript-react-example] ( https://github.com/ethul/purescript-react-example )
31+
32+ ## Troubleshooting
33+
34+ #### How to use JavaScript components?
35+
36+ To use a React component that is published as a JavaScript module, one
37+ can leverage PureScript's FFI to define a type for the component and its
38+ props. Consider the following example.
39+
40+ ``` purescript
41+ module Clock (clockComponent) where
42+
43+ import React (ReactClass, SyntheticEventHandler, Children)
44+ import React.SyntheticEvent (SyntheticEvent)
45+
46+ foreign import clockComponent
47+ :: ReactClass
48+ { children :: Children
49+ , format :: String
50+ , className :: String
51+ , onTick :: SyntheticEventHandler SyntheticEvent
52+ }
53+ ```
54+
55+ Rendering the ` clockComponent ` can be done as follows.
56+
57+ ``` purescript
58+ module Component where
59+
60+ import Prelude
61+
62+ import React as React
63+
64+ import Clock as Clock
65+
66+ clock :: React.ReactElement
67+ clock =
68+ React.createElement Clock.clockComponent
69+ { format: "HH:mm:ss"
70+ , className: "test-class-name"
71+ , onTick: React.handle $ \event -> do
72+ React.preventDefault event
73+ -- etc.
74+ pure unit
75+ } []
76+ ```
77+
78+ A consideration when defining a type for an external component is that
79+ some components pass their props through to a DOM element. In a case
80+ such as this, it can be helpful to leverage the props defined in the
81+ ` React.DOM.Props ` module. One way to accomplish this is to define the
82+ external component as follows.
83+
84+ ``` purescript
85+ module Clock
86+ ( clockComponent
87+ , format
88+ , onTick
89+ ) where
90+
91+ import Prelude
92+
93+ import React (ReactClass, ReactElement, SyntheticEventHandlerContext, Children, createElement, handle)
94+ import React.SyntheticEvent (SyntheticEvent)
95+ import React.DOM.Props (Props, unsafeFromPropsArray, unsafeMkProps)
96+
97+ clockComponent :: Array Props -> Array ReactElement -> ReactElement
98+ clockComponent props children = createElement clockComponent_ (unsafeFromPropsArray props :: {}) children
99+
100+ format :: String -> Props
101+ format = unsafeMkProps "format"
102+
103+ onTick :: forall eff props state. (SyntheticEvent -> SyntheticEventHandlerContext eff props state Unit) -> Props
104+ onTick k = unsafeMkProps "onTick" (handle k)
105+
106+ foreign import clockComponent_
107+ :: ReactClass
108+ { children :: Children
109+ }
110+ ```
111+
112+ Rendering the ` clockComponent ` can be done as follows.
113+
114+ ``` purescript
115+ module Component where
116+
117+ import Prelude
118+
119+ import React as React
120+ import React.DOM.Props as Props
121+
122+ import Clock as Clock
123+
124+ clock :: React.ReactElement
125+ clock =
126+ Clock.clockComponent
127+ [ Clock.format "HH:mm:ss"
128+ , Clock.onTick $ \event -> do
129+ React.preventDefault event
130+ -- etc.
131+ pure unit
132+ , Props.className "test-class-name"
133+ , Props.style
134+ { fontWeight: "bold"
135+ , color: "blue"
136+ }
137+ -- additional Props.*
138+ ]
139+ [ ]
140+ ```
141+
142+ #### Components with type class constraints re-mount on every render?
143+
144+ Consider the following example where an ordered list component is
145+ defined for any item of type ` a ` , where ` a ` is constrained to have an
146+ ` Ord ` type class instance.
147+
148+ ``` purescript
149+ module OrderedList where
150+
151+ import Prelude
152+
153+ import Data.Array (sort)
154+
155+ import React as React
156+ import React.DOM as DOM
157+ import Debug.Trace as Trace
158+
159+ type OrderedListProps a
160+ = { items :: Array a
161+ , renderItem :: a -> React.ReactElement
162+ }
163+
164+ orderedList :: forall a. Ord a => React.ReactClass (OrderedListProps a)
165+ orderedList = React.component "OrderedList" component
166+ where
167+ component this =
168+ pure { state: {}
169+ , componentDidMount: do
170+ _ <- pure $ Trace.spy "OrderedList.componentDidMount"
171+ pure unit
172+ , render: render <$> React.getProps this
173+ }
174+ where
175+ render
176+ { items
177+ , renderItem
178+ } =
179+ DOM.ol [ ] $
180+ renderItem' <$> sort items
181+ where
182+ renderItem' a =
183+ DOM.li
184+ [ ]
185+ [ renderItem a ]
186+
187+ -- This would be defined where the type parameter `a` is known.
188+
189+ orderedListInt :: React.ReactClass (OrderedListProps Int)
190+ orderedListInt = orderedList
191+ ```
192+
193+ If the component ` orderedList ` above were to be rendered, the debugging
194+ statement ` OrderedList.componentDidMount ` is printed to the console each
195+ time the parent component is rendered. The reason for this is due to how
196+ the ` orderedList ` component is compiled to JavaScript.
197+
198+ ``` javascript
199+ var orderedList = function (dictOrd ) {
200+ var component = function ($$this ) {
201+ // ...
202+ };
203+ return React .component ()(" OrderedList" )(component);
204+ };
205+ ```
206+
207+ Above, the component creation is wrapped by the function with the
208+ ` dictOrd ` parameter. This means that a new component is being created on
209+ each render of the component using ` orderedList ` . This may not be ideal
210+ in all cases; e.g., if ` orderedList ` had needed to store state.
211+
212+ To avoid ` orderedList ` from being recreated each time, a function can be
213+ defined that specifies the type parameter with the type class contraint.
214+ If the component using the ordered list knows that the items are of type
215+ ` Int ` , the component can define ` orderedListInt ` as shown above, and use
216+ it to render the ordered list instead of ` orderedList ` .
0 commit comments