Skip to content

Commit f0197be

Browse files
author
Michael Trotter
committed
Docs
1 parent 9e7f205 commit f0197be

19 files changed

Lines changed: 635 additions & 105 deletions

File tree

README.md

Lines changed: 9 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,16 @@
22

33
[![Build Status](https://travis-ci.org/lumihq/purescript-react-basic.svg?branch=master)](https://travis-ci.org/lumihq/purescript-react-basic)
44

5-
This package implements an opinionated set of bindings to the React library, optimizing for the most basic use cases.
5+
This package implements an opinionated set of bindings over [React](https://reactjs.org), optimizing for correctness and simplifying basic use cases.
66

77
## Features
88

99
- All React DOM elements and attributes are supported (soon, events are a work in progress).
10-
- An intuitive API for specifying props - no arrays of key value pairs, just records.
10+
- An intuitive API for specifying props - simple records, no arrays of key value pairs.
1111
- Attributes are optional, but type-checked. It is a type error to specify `href` as an integer, for example.
12+
- An action/update pattern for local component state, inspired by [ReasonReact](https://reasonml.github.io/reason-react/).
13+
- React lifecycles are available, but not in your way when you don't need them.
14+
- Typeclasses, like `Eq props`, can be used in component definitions.
1215

1316
## Getting Started
1417

@@ -18,49 +21,8 @@ You can install this package using Bower:
1821
bower install git@github.com:lumihq/purescript-react-basic.git
1922
```
2023

21-
Here is an example component which renders a label read from props along with a counter:
24+
See [the documentation](./docs/React.Basic) for a detailed overview, or take a look at one of the examples:
2225

23-
```purescript
24-
module Counter where
25-
26-
import Prelude
27-
28-
import React.Basic as React
29-
import React.Basic.DOM as R
30-
import React.Basic.Events as Events
31-
32-
-- The props for the component
33-
type Props =
34-
{ label :: String
35-
}
36-
37-
-- Create a component by passing a record to the `react` function.
38-
-- The `render` function takes the props and current state, as well as a
39-
-- state update callback, and produces a document.
40-
component :: React.Component Props
41-
component = React.component { displayName: "Counter", initialState, receiveProps, render }
42-
where
43-
initialState =
44-
{ counter: 0
45-
}
46-
47-
receiveProps _ =
48-
pure unit
49-
50-
render { props, state, setState } =
51-
R.button
52-
{ onClick: Events.handler_ do
53-
setState \s -> s { counter = s.counter + 1 }
54-
, children: [ R.text (props.label <> ": " <> show state.counter) ]
55-
}
56-
```
57-
58-
This component can be used directly from JavaScript. For example, if you are using `purs-loader`:
59-
60-
```jsx
61-
import {example as Example} from 'React.Basic.Example.purs';
62-
63-
const myComponent = () => (
64-
<Example label='Increment' />
65-
);
66-
```
26+
- [A Counter](./examples/counter/src/Counter.purs)
27+
- [A controlled input](./examples/controlled-input/src/ControlledInput.purs)
28+
- [Components](./examples/component/src/ToggleButton.purs) in [components](./examples/component/src/Container.purs)
Lines changed: 58 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
#### `ComponentSpec`
44

55
``` purescript
6-
type ComponentSpec props state initialState action = { initialState :: initialState, update :: Self props state action -> action -> StateUpdate props state action, render :: Self props state action -> JSX, shouldUpdate :: Self props state action -> props -> state -> Boolean, didMount :: Self props state action -> Effect Unit, didUpdate :: Self props state action -> Effect Unit, willUnmount :: Self props state action -> Effect Unit, "$$type" :: ComponentType props state action }
6+
type ComponentSpec props state action = (initialState :: state, update :: Self props state action -> action -> StateUpdate props state action, render :: Self props state action -> JSX, shouldUpdate :: Self props state action -> props -> state -> Boolean, didMount :: Self props state action -> Effect Unit, didUpdate :: Self props state action -> Effect Unit, willUnmount :: Self props state action -> Effect Unit)
77
```
88

99
`ComponentSpec` represents a React-Basic component implementation.
@@ -13,7 +13,7 @@ with specific implementations. None are required to be overridden, unless
1313
an overridden function interacts with `state`, in which case `initialState`
1414
is required (the compiler enforces this). While you _can_ use `state` and
1515
dispatch actions without defining `update`, doing so doesn't make much sense
16-
so the default `update` implementation will emit a warning.
16+
and will emit a warning.
1717

1818
- `initialState`
1919
- The component's starting state.
@@ -26,7 +26,7 @@ so the default `update` implementation will emit a warning.
2626
- `render`
2727
- Takes a current snapshot of the component (`Self`) and converts it to renderable `JSX`.
2828
- `shouldUpdate`
29-
- Can be useful for occasional performance optimizations. Rarely necessary.
29+
- Can be useful for performance optimizations. Rarely necessary.
3030
- `didMount`
3131
- The React component's `componentDidMount` lifecycle. Useful for initiating an action on first mount, such as fetching data from a server.
3232
- `didUpdate`
@@ -35,14 +35,13 @@ so the default `update` implementation will emit a warning.
3535
- The React component's `componentWillUpdate` lifecycle. Any subscriptions or timers created in `didMount` or `didUpdate` should be disposed of here.
3636

3737
The component spec is generally not exported from your component
38-
module and this type is rarely used explicitly. The simplified alias
39-
`Component` is usually sufficient, and `make` will validate whether
40-
your component's types line up.
38+
module and this type is rarely used explicitly. `make` will validate whether
39+
your component's internal types line up.
4140

4241
For example:
4342

4443
```purs
45-
component :: Component
44+
component :: Component Props
4645
component = createComponent "Counter"
4746
4847
type Props =
@@ -53,14 +52,14 @@ data Action
5352
= Increment
5453
5554
counter :: Props -> JSX
56-
counter = make component
55+
counter: make component
5756
{ initialState = { counter: 0 }
5857
59-
, update = \self action -> case action of
58+
, update: \self action -> case action of
6059
Increment ->
6160
Update self.state { counter = self.state.counter + 1 }
6261
63-
, render = \self ->
62+
, render: \self ->
6463
R.button
6564
{ onClick: capture_ self Increment
6665
, children: [ R.text (self.props.label <> ": " <> show self.state.counter) ]
@@ -73,53 +72,54 @@ This example component overrides `initialState`, `update`, and `render`.
7372
__*Note:* A `ComponentSpec` is *not* a valid React component by itself. If you would like to use
7473
a React-Basic component from JavaScript, use `toReactComponent`.__
7574

76-
__*Note:* `$$type` is for internal use only. It needs to be on the type to
77-
preserve its existence during a record update, as in the example above.__
78-
7975
__*See also:* `Component`, `ComponentSpec`, `make`, `makeStateless`__
8076

8177
#### `createComponent`
8278

8379
``` purescript
84-
createComponent :: forall props state action. String -> ComponentSpec props state Unit action
80+
createComponent :: forall props. String -> Component props
8581
```
8682

87-
Creates a `ComponentSpec` with a given Display Name.
83+
Creates a `Component` with a given Display Name.
8884

8985
The resulting component spec is usually given the simplified `Component` type:
9086

9187
```purs
92-
component :: Component
88+
component :: Component Props
9389
component = createComponent "Counter"
9490
```
9591

9692
This function should be used at the module level and considered side effecting.
9793
This is because React uses referential equality when deciding whether a new
98-
`JSX` tree is a valid update, or if it needs to be replaced entirely
94+
`JSX` tree is a valid update or if it needs to be replaced entirely
9995
(expensive and clears component state lower in the tree).
10096

97+
__*Note:* A specific type for the props in `Component props` should always be chosen at this point.
98+
It's technically possible to declare the component with `forall props. Component props`
99+
but doing so is unsafe. Leaving the prop type open allows the use of a single `Component`
100+
definition in multiple React-Basic components that may have different prop types. Because
101+
component lifecycles are managed by React, it becomes possible for incompatible prop values to
102+
be passed by React into lifecycle functions.__
103+
101104
__*Note:* A `Component` is *not* a valid React component by itself. If you would like to use
102105
a React-Basic component from JavaScript, use `toReactComponent`.__
103106

104-
__*See also:* `Component`, `ComponentSpec`, `make`, `makeStateless`__
107+
__*See also:* `Component`, `make`, `makeStateless`__
105108

106109
#### `Component`
107110

108111
``` purescript
109-
type Component = forall props state action. ComponentSpec props state Unit action
112+
data Component props
110113
```
111114

112115
A simplified alias for `ComponentSpec`. This type is usually used to represent
113116
the default component type returned from `createComponent`.
114-
115-
#### `ComponentType`
116-
117-
``` purescript
118-
data ComponentType props state action
119-
```
120-
121117
Opaque component information for internal use.
122118

119+
__*Note:* Never define a component with
120+
a less specific type for `props` than its associated `ComponentSpec` and `make`
121+
calls, as this can lead to unsafe interactions with React's lifecycle management.__
122+
123123
__*For the curious:* This is the "class" React will use to render and
124124
identify the component. It receives the `ComponentSpec` as a prop and knows
125125
how to defer behavior to it. It requires very specific props and is not useful by
@@ -138,7 +138,7 @@ data StateUpdate props state action
138138
Used by the `update` function to describe the kind of state update and/or side
139139
effects desired.
140140

141-
__*See also:* `ComponentSpec`__
141+
__*See also:* `ComponentSpec`, `capture`__
142142

143143
#### `Self`
144144

@@ -255,14 +255,14 @@ __*See also:* `Self`__
255255
#### `make`
256256

257257
``` purescript
258-
make :: forall props state action. ComponentSpec props state state action -> props -> JSX
258+
make :: forall spec spec_ props state action. Union spec spec_ (ComponentSpec props state action) => Component props -> { render :: Self props state action -> JSX | spec } -> props -> JSX
259259
```
260260

261-
Turn a `Component` into a usable render function.
261+
Turn a `Component` and `ComponentSpec` into a usable render function.
262262
This is where you will want to provide customized implementations:
263263

264264
```purs
265-
component :: Component
265+
component :: Component Props
266266
component = createComponent "Counter"
267267
268268
type Props =
@@ -274,13 +274,13 @@ data Action
274274
275275
counter :: Props -> JSX
276276
counter = make component
277-
{ initialState = { counter: 0 }
277+
{ initialState: { counter: 0 }
278278
279-
, update = \self action -> case action of
279+
, update: \self action -> case action of
280280
Increment ->
281281
Update self.state { counter = self.state.counter + 1 }
282282
283-
, render = \self ->
283+
, render: \self ->
284284
R.button
285285
{ onClick: capture_ self Increment
286286
, children: [ R.text (self.props.label <> ": " <> show self.state.counter) ]
@@ -293,13 +293,13 @@ __*See also:* `makeStateless`, `createComponent`, `Component`, `ComponentSpec`__
293293
#### `makeStateless`
294294

295295
``` purescript
296-
makeStateless :: forall props. ComponentSpec props Unit Unit Unit -> (props -> JSX) -> props -> JSX
296+
makeStateless :: forall props. Component props -> (props -> JSX) -> props -> JSX
297297
```
298298

299299
Makes stateless component definition slightly less verbose:
300300

301301
```purs
302-
component :: Component
302+
component :: Component Props
303303
component = createComponent "Xyz"
304304
305305
myComponent :: Props -> JSX
@@ -398,6 +398,28 @@ imported from FFI.
398398

399399
__*See also:* `ReactComponent`, `element`, React's documentation regarding the special `key` prop__
400400

401+
#### `displayNameFromComponent`
402+
403+
``` purescript
404+
displayNameFromComponent :: forall props. Component props -> String
405+
```
406+
407+
Retrieve the Display Name from a `ComponentSpec`. Useful for debugging and improving
408+
error messages in logs.
409+
410+
__*See also:* `displayNameFromSelf`, `createComponent`__
411+
412+
#### `displayNameFromSelf`
413+
414+
``` purescript
415+
displayNameFromSelf :: forall props state action. Self props state action -> String
416+
```
417+
418+
Retrieve the Display Name from a `Self`. Useful for debugging and improving
419+
error messages in logs.
420+
421+
__*See also:* `displayNameFromComponent`, `createComponent`__
422+
401423
#### `ReactComponent`
402424

403425
``` purescript
@@ -426,7 +448,7 @@ caution.
426448
#### `toReactComponent`
427449

428450
``` purescript
429-
toReactComponent :: forall jsProps props state action. ({ | jsProps } -> props) -> ComponentSpec props state state action -> ReactComponent { | jsProps }
451+
toReactComponent :: forall spec spec_ jsProps props state action. Union spec spec_ (ComponentSpec props state action) => ({ | jsProps } -> props) -> Component props -> { render :: Self props state action -> JSX | spec } -> ReactComponent { | jsProps }
430452
```
431453

432454
Convert a React-Basic `ComponentSpec` to a JavaScript-friendly React component.

0 commit comments

Comments
 (0)