Skip to content

Update React page #593

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 28 commits into from
Nov 25, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
a8ed657
add React v0.10.0 page
mununki Nov 5, 2022
cb98199
remove migration from react latest and
mununki Nov 5, 2022
3230a82
update introduction
mununki Nov 6, 2022
7baa1f4
update installation
mununki Nov 6, 2022
6ee8212
rename to migrate-from-v3
mununki Nov 6, 2022
9032111
add migrate from v3 page
mununki Nov 6, 2022
7298e51
add toc for extensions of props page
mununki Nov 6, 2022
e3a3416
update element and jsx page
mununki Nov 7, 2022
bb26f7a
update rendering-elements page
mununki Nov 7, 2022
e879b67
update components and props page
mununki Nov 10, 2022
be5a84f
update context page
mununki Nov 10, 2022
0ad6b84
update hooks-context page
mununki Nov 10, 2022
eab6d5b
update beyond jsx page
mununki Nov 10, 2022
2f53019
update forwarding-refs page
mununki Nov 10, 2022
ac95e33
update extensions of props page
mununki Nov 10, 2022
8cac94b
fix beyond jsx page
mununki Nov 10, 2022
0c07c9e
remove react.component from expanded
mununki Nov 11, 2022
9edae92
remove react.component
mununki Nov 11, 2022
9e334f1
add extensions of props page
mununki Nov 11, 2022
4d04878
Update pages/docs/react/latest/installation.mdx
mununki Nov 11, 2022
71e2dcd
remove the flow support of gentype
mununki Nov 11, 2022
ad5cde1
Update pages/docs/react/latest/beyond-jsx.mdx
mununki Nov 11, 2022
a9b7804
Update pages/docs/react/latest/beyond-jsx.mdx
mununki Nov 11, 2022
dfc240f
Update pages/docs/react/latest/migrate-from-v3.mdx
mununki Nov 11, 2022
d7107b4
Update pages/docs/react/latest/migrate-from-v3.mdx
mununki Nov 11, 2022
5e43270
add make function name comment
mununki Nov 11, 2022
3671316
Update pages/docs/react/latest/migrate-from-v3.mdx
mununki Nov 11, 2022
d082ac4
add automatic codes
mununki Nov 11, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions data/sidebar_react_latest.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"Overview": [
"introduction",
"installation",
"migrate-from-reason-react"
"migrate-from-v3"
],
"Main Concepts": [
"elements-and-jsx",
Expand All @@ -25,6 +25,7 @@
],
"Guides": [
"beyond-jsx",
"forwarding-refs"
"forwarding-refs",
"extensions-of-props"
]
}
}
30 changes: 30 additions & 0 deletions data/sidebar_react_v0100.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"Overview": [
"introduction",
"installation",
"migrate-from-reason-react"
],
"Main Concepts": [
"elements-and-jsx",
"rendering-elements",
"components-and-props",
"arrays-and-keys",
"refs-and-the-dom",
"context",
"styling",
"router"
],
"Hooks & State Management": [
"hooks-overview",
"hooks-effect",
"hooks-state",
"hooks-reducer",
"hooks-context",
"hooks-ref",
"hooks-custom"
],
"Guides": [
"beyond-jsx",
"forwarding-refs"
]
}
118 changes: 60 additions & 58 deletions pages/docs/react/latest/beyond-jsx.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ JSX is a syntax sugar that allows us to use React components in an HTML like man

</Intro>

**Note:** This section requires knowledge about the low level apis for [creating elements](./elements-and-jsx#creating-elements-from-component-functions), such as `React.createElement` or `ReactDOMRe.createDOMElementVariadic`.
**Note:** This section requires knowledge about the low level apis for [creating elements](./elements-and-jsx#creating-elements-from-component-functions), such as `React.createElement` or `ReactDOM.createDOMElementVariadic`.

> **Note:** This page assumes your `bsconfig.json` to be set to `"reason": { "react-jsx": 3 }` to apply the right JSX transformations.
> **Note:** This page assumes your `bsconfig.json` to be set to `"jsx": { "version": 4 }` to apply the right JSX transformations.

## Component Types

Expand All @@ -24,22 +24,19 @@ Here are some examples on how to define your own component types (often useful w

```res
// Plain function type
type friendComp =
({"name": string, "online": bool}) => React.element;
type friend = {name: string, online: bool}
type friendComp = friend => React.element

// Equivalent to
// ({"padding": string, "children": React.element}) => React.element
type containerComp =
React.component<{
"padding": string,
"children": React.element
}>;
// ({padding: string, children: React.element}) => React.element
type props = {padding: string, children: React.element}
type containerComp = React.component<props>
```
The types above are pretty low level (basically the JS representation of a React component), but since ReScript React has its own ways of defining React components in a more language specific way, let's have a closer look on the anatomy of such a construct.

## JSX Component Interface

A ReScript React component needs to be a (sub-)module with a `make` and `makeProps` function to be usable in JSX. To make things easier, we provide a `@react.component` decorator to create those functions for you:
A ReScript React component needs to be a (sub-)module with a `make` function and `props` type to be usable in JSX. To make things easier, we provide a `@react.component` decorator to create those functions for you:

<CodeTab labels={["Decorated", "Expanded"]}>

Expand All @@ -56,15 +53,13 @@ module Friend = {
```
```res
module Friend = {
@obj
external makeProps: (
~name: string,
~children: 'children,
~key: string=?,
unit) => {"name": string, "children": 'children} = "";

let make = (props: {"name": string, "children": 'children}) => {
// React element creation from the original make function
type props<'name, 'children> = {
name: 'name,
children: 'children,
}

let make = ({name, children, _}: props<string, 'children>) => {
ReactDOM.createDOMElementVariadic("div", [{React.string(name)}, children])
}
}
```
Expand All @@ -73,11 +68,9 @@ module Friend = {

In the expanded output:

- `makeProps`: A function that receives multiple labeled arguments (according to prop names) and returns the value that is consumed by make(props)
- `props`: A generated record type that has fields according to the labeled arguments of the `make` function
- `make`: A converted `make` function that complies to the component interface `(props) => React.element`

**Note:** The `makeProps` function will also always contain a `~key` prop.

### Special Case React.forwardRef

The `@react.component` decorator also works for `React.forwardRef` calls:
Expand All @@ -88,64 +81,58 @@ The `@react.component` decorator also works for `React.forwardRef` calls:
```res
module FancyInput = {
@react.component
let make = React.forwardRef((~className=?, ~children, ref_) =>
let make = React.forwardRef((~className=?, ~children, ref) =>
<div>
// use ref_ here
// use ref here
</div>
)
}
```

```res
// Simplified Output
module FancyInput = {
@obj
external makeProps: (
~className: 'className=?,
~children: 'children,
~key: string=?,
~ref: 'ref=?,
unit,
) => {"className": option<'className>, "children": 'children} = ""

let make =
(~className=?, ~children) => ref_ => ReactDOMRe.createDOMElementVariadic("div", [])

let make = React.forwardRef(
(props: {"className": option<'className>, "children": 'children}, ref_,) => {
make(
~className=props["className"],
~children=props["children"],
ref_)
})
type props<'className, 'children, 'ref> = {
className?: 'className,
children: 'children,
ref?: 'ref,
}

let make = (
{?className, children, _}: props<'className, 'children, ReactRef.currentDomRef>,
ref: Js.Nullable.t<ReactRef.currentDomRef>,
) =>
make(~className, ~children, ~ref, ())
```

</CodeTab>

As shown in the expanded output above, our decorator desugars the function passed to `React.forwardRef` in the same manner as a typical component `make` function. It also creates a `makeProps` function with a `ref` prop, so we can use it in our JSX call (`<FancyInput ref=.../>`).
As shown in the expanded output above, our decorator desugars the function passed to `React.forwardRef` in the same manner as a typical component `make` function. It also creates a `props` type with an optional `ref` field, so we can use it in our JSX call (`<FancyInput ref=.../>`).

So now that we know how the ReScript React component transformation works, let's have a look on how ReScript transforms our JSX constructs.

## JSX Under the Hood

Whenever we are using JSX with a custom component ("capitalized JSX"), we are actually using `React.createElement` to create a new element. Here is an example of a React component without children:

<CodeTab labels={["JSX", "Without JSX"]}>
<CodeTab labels={["JSX", "Without JSX", "JS Output"]}>

```res
<Friend name="Fred" age=1 />
<Friend name="Fred" age=20 />
```
```res
React.createElement(Friend.make, Friend.makeProps(~name="Fred", ~age=1, ()))
// classic
React.createElement(Friend.make, {name: "Fred", age:20})

// automatic
React.jsx(Friend.make, {name: "Fred", age: 20})
```
```js
React.createElement(Playground$Friend, { name: "Fred", age: 20 });
```

</CodeTab>

As you can see, it uses `Friend.make` and `Friend.makeProps` to call the `React.createElement` API. In case you are providing children, it will use `React.createElementVariadic` instead (which is just a different binding for `React.createElement`):
As you can see, it uses `Friend.make` to call the `React.createElement` API. In case you are providing children, it will use `React.createElementVariadic` instead (which is just a different binding for `React.createElement`):

<CodeTab labels={["JSX", "Without JSX", "JS Output"]}>

Expand All @@ -157,11 +144,18 @@ As you can see, it uses `Friend.make` and `Friend.makeProps` to call the `React.
```

```res
// classic
React.createElementVariadic(
Container.make,
Container.makeProps(~width=200, ~children=React.null, ()),
{width: 200, children: React.null},
[{React.string("Hello")}, {React.string("World")}],
)

// automatic
React.jsxs(
Container.make,
{width: 200, children: React.array([{React.string("Hello")}, {React.string("World")}])},
)
```

```js
Expand All @@ -170,12 +164,12 @@ React.createElement(Container, { width: 200, children: null }, "Hello", "World")

</CodeTab>

Note that the `~children=React.null` prop has no relevance since React will only care about the children array passed as a third argument.
Note that the `children: React.null` field has no relevance since React will only care about the children array passed as a third argument.


### Dom Elements

"Uncapitalized JSX" expressions are treated as DOM elements and will be converted to `ReactDOMRe.createDOMElementVariadic` calls:
"Uncapitalized JSX" expressions are treated as DOM elements and will be converted to `ReactDOM.createDOMElementVariadic` calls:

<CodeTab labels={["JSX", "Without JSX", "JS Output"]}>

Expand All @@ -184,11 +178,15 @@ Note that the `~children=React.null` prop has no relevance since React will only
```

```res
ReactDOMRe.createDOMElementVariadic("div", ~props=ReactDOMRe.domProps(~title="test", ()), [])
// classic
ReactDOM.createDOMElementVariadic("div", ~props={title: "test"}, [])

// automatic
ReactDOM.jsx("div", {title: "test"})
```

```js
React.createElement("div", { title: "test" });
React.createElement("div", { title: "test" });
```

</CodeTab>
Expand All @@ -204,11 +202,15 @@ The same goes for uncapitalized JSX with children:
```

```res
ReactDOMRe.createDOMElementVariadic(
// classic
ReactDOM.createDOMElementVariadic(
"div",
~props=ReactDOMRe.domProps(~title="test", ()),
[ReactDOMRe.createDOMElementVariadic("span", [])],
~props={title: "test"},
[ReactDOM.createDOMElementVariadic("span", [])],
)

// automatic
ReactDOM.jsx("div", {title: "test", children: ?ReactDOM.someElement(ReactDOM.jsx("span", {}))})
```

```js
Expand Down
Loading