Skip to content

Commit 4448df8

Browse files
danyx23alfonsogarciacaro
authored andcommitted
First stab at documentation on how to use third party react components
1 parent f5ac5d0 commit 4448df8

File tree

2 files changed

+91
-0
lines changed

2 files changed

+91
-0
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ Fable bindings and helpers for React projects
55
## Documents
66

77
* [Server-Side Rendering tutorial](docs/server-side-rendering.md): A **Pure F#** solution for SSR, **No NodeJS Required!**
8+
* [Using third party React components](docs/using-third-party-react-components.md): How to create binding so that third party Javascript React components can be used like stock React components in Fable code.
89

910

1011

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
# Using third party React components
2+
3+
Using a third party (Javascript) React component is straightforward for most components. There are two ways of declaring a third party React component in F# - either by declaring a Pojo record for the props or by declaring a Discriminated Union where each case has one field.
4+
5+
Some components have a [Typescript](https://www.typescriptlang.org/) definition available, either because the component was authored in Typescript or someone created a type definition for the [Definitely Typed project](https://definitelytyped.org/). If this is the case then you can try the [ts2fable tool](https://github.com/fable-compiler/ts2fable) to convert this React component type definition from Typescript to a Fable type declaration - it might need some tweaking but for components with a big API surface this can be a real time safer.
6+
7+
The basic steps when working with a Discriminated Union are:
8+
9+
### 1. Install the react component
10+
11+
Using yarn or npm, install the react component you want to use.
12+
13+
For example to use the [rc-progress React components](https://github.com/react-component/progress), run the following in your Fable project root:
14+
15+
```bash
16+
yarn install rc-progress
17+
```
18+
19+
### 2. Define the props type
20+
21+
Reference the **documentation of the React component** to find out which props the component supports and declare them as an F# type (see below for the two supported mechanisms). You can define only a subset of supported props in F# if you don't need to cover the full props options that the React component supports.
22+
23+
For example to expose the percent, strokeWidth and strokeColor props of the rc-progress components:
24+
25+
```fsharp
26+
type ProgressProps =
27+
| Percent of int
28+
| StrokeWidth of int
29+
| StrokeColor of string
30+
```
31+
32+
If one of the props is treated as a string enum in Javascript (e.g. if there is a size prop with the supported values "small", "normal" and "big"), then the `[<StringEnum>]` attribute can be very useful for defining helper types:
33+
34+
```fsharp
35+
[<StringEnum>]
36+
type Size =
37+
| Small
38+
| Normal
39+
| Big
40+
41+
type SomeComponentProps =
42+
| Size of Size
43+
| ...
44+
```
45+
46+
### 3. Define the React component creation function
47+
48+
Using the `ofImport` function you instruct Fable which component should be instantiated when the creation function is called.
49+
50+
In the example of rc-progress, to declare a `progressLine` creation function that imports the `Line` component from the library `rc-progress`, you would declare it as follows.
51+
52+
Note the `keyValueList` function that is used to convert the props of type `IProgressProps list` to a Javascript object where they key is the lower case name of the DU case identifier and the value is the field value of the DU (e.g. if the list that is passed into the function is `[Percent 40; StrokeColor "red"]`, the Javascript object that will be passed to the `props` of the `Line` react component would look like this: `{ percent: 40, strokeColor: "red" }`)
53+
54+
```fsharp
55+
let inline progressLine (props : ProgressProps list) (elems : ReactElement list) : ReactElement =
56+
ofImport "Line" "rc-progress" (keyValueList CaseRules.LowerFirst props) elems
57+
```
58+
59+
### 4. Use the creation function in your view code
60+
61+
The function you declared in step 2 now behaves just like any other React component function.
62+
63+
To use the component in a [Fable-Elmish](https://fable-elmish.github.io/elmish/) view function:
64+
65+
```fsharp
66+
let view (model : Model) (dispatch : Msg -> unit) =
67+
div
68+
[]
69+
[ progressLine [ percent model.currentProgress; strokeColor: "red" ] [] ]
70+
```
71+
72+
## Dynamic import using a Pojo
73+
74+
The dynamic import is similar to the approach above, but instead of declaring a DU you create a Pojo record. This looks more like normal F# code but can be unwieldy if you have a lot of optional props (which is often the case in complex React components)
75+
76+
```fsharp
77+
[<Pojo>]
78+
type ProgressProps =
79+
{ percent : int
80+
strokeWidth : int
81+
strokeColor : string
82+
}
83+
84+
let inline progressLine (props : ProgressProps) (elems : ReactElement list) : ReactElement =
85+
ofImport "Line" "rc-progress" props elems
86+
```
87+
88+
## Edgecases
89+
90+
This documentation needs to be extended to cover [Higher Order Components](https://reactjs.org/docs/higher-order-components.html) and maybe [Context]()https://reactjs.org/docs/context.html, [Fragments](https://reactjs.org/docs/fragments.html) etc. Contributions are welcome!

0 commit comments

Comments
 (0)