Skip to content

Prepare for 0.16.0 #893

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

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
10 changes: 10 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# Unreleased

* FEATURE: add color to domProps (@tatchy in https://github.com/reasonml/reason-react/pull/871)
* BREAKING: Support for React 19 (@davesnx in #846)
* DOCS: Documentation updates for 0.16 (@davesnx in https://github.com/reasonml/reason-react/pull/864)
* INFRA: Update deps (@johnhaley81 in https://github.com/reasonml/reason-react/pull/876)
* INFRA: update setup-ocaml to v3 (@anmonteiro in https://github.com/reasonml/reason-react/pull/878)
* FIX: Remove raise annotations and fix locations on errors (@davesnx https://github.com/reasonml/reason-react/pull/863)
* FIX: type of pipeable stream to allow objects with keys (@anmonteiro in https://github.com/reasonml/reason-react/pull/854)
* FEATURE: Add `preconnect`, `prefetchDNS`, `preinit`, `preinitModule`, `preload` and `preloadModule` in ReactDOM.Experimental (@r17x in https://github.com/reasonml/reason-react/pull/849)
* BREAKING: Make lowerbound be Melange 5.1 (due to Js.FormData.t usage)

# 0.15.0

* Add `isValidElement` (@r17x in
Expand Down
8 changes: 4 additions & 4 deletions demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@
"melange.belt/": "./demo/node_modules/melange.belt/",
"melange.js/": "./demo/node_modules/melange.js/",
"reason-react/": "./demo/node_modules/reason-react/",
"react/jsx-runtime": "https://esm.sh/react@19.0.0-rc.1/jsx-runtime",
"react": "https://esm.sh/react@19.0.0-rc.1",
"react-dom": "https://esm.sh/react-dom@19.0.0-rc.1",
"react-dom/client": "https://esm.sh/react-dom@19.0.0-rc.1/client"
"react/jsx-runtime": "https://esm.sh/react@19.1.0/jsx-runtime?dev",
"react": "https://esm.sh/react@19.1.0?dev",
"react-dom": "https://esm.sh/react-dom@19.1.0?dev",
"react-dom/client": "https://esm.sh/react-dom@19.1.0/client?dev"
}
}
</script>
Expand Down
56 changes: 55 additions & 1 deletion demo/main.re
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,59 @@ module UseReducerNoProblemo = {
};
};

module FragmentsEverywhere = {
[@react.component]
let make = () => {
let items = ["Apple", "Banana", "Cherry", "Date"];
let numbers = [1, 2, 3, 4, 5];

<section>
<h3> {React.string("Fragments Everywhere")} </h3>
<React.Fragment>
<p> {React.string("This is inside a fragment")} </p>
<span> {React.string("Multiple elements together")} </span>
<small> {React.string("Without a wrapper div")} </small>
</React.Fragment>
<div>
<h4> {React.string("List of items with fragments:")} </h4>
{items
|> List.mapi((index, item) =>
<React.Fragment key={string_of_int(index)}>
<strong> {React.string(item)} </strong>
<span>
{React.string(" - Item #" ++ string_of_int(index + 1))}
</span>
<br />
</React.Fragment>
)
|> Array.of_list
|> React.array}
</div>
<>
<hr />
<p> {React.string("Another fragment section")} </p>
<button> {React.string("Click me")} </button>
<em> {React.string("Emphasized text")} </em>
</>
<div>
<h4> {React.string("Numbers with fragments:")} </h4>
{numbers
|> List.mapi((index, num) =>
<React.Fragment key={string_of_int(num)}>
<div> {React.string("Number: " ++ string_of_int(num))} </div>
<small>
{React.string("Square: " ++ string_of_int(num * num))}
</small>
<br />
</React.Fragment>
)
|> Array.of_list
|> React.array}
</div>
</section>;
};
};

module App = {
[@react.component]
let make = (~initialValue) => {
Expand All @@ -174,7 +227,8 @@ module App = {
<RerenderOnEachClick key="rerender-on-each-click" value=0 callback />
<WithLayoutEffect key="layout-effect" value callback />
<WithRefAndEffect key="ref-and-effect" callback />
<UseReducerNoProblemo />
<UseReducerNoProblemo key="use-reducer-no-problemo" />
<FragmentsEverywhere key="fragments-everywhere" />
</main>;
};
};
Expand Down
68 changes: 40 additions & 28 deletions docs/jsx.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,19 @@
title: JSX
---

Reason comes with the [JSX](https://reasonml.github.io/docs/en/jsx.html) syntax! ReasonReact works very similar to how [the ReactJS JSX transform](https://reactjs.org/docs/introducing-jsx.html) does.
Reason comes with [JSX](https://reasonml.github.io/docs/en/jsx.html) syntax. Enables representation of HTML-like expressions within the language.

reason-react enables [the ReactJS JSX transform](https://reactjs.org/docs/introducing-jsx.html) in Reason.

Since `reason-react.0.12.0`, the JSX transformation currently supports the [New JSX Transform](https://legacy.reactjs.org/blog/2020/09/22/introducing-the-new-jsx-transform.html). JSX functions are imported from `react/jsx-runtime`. Previous versions of reason-react used the legacy API `React.createElement`.

# Install

To use it, you would need to install [`reason-react-ppx`](https://opam.ocaml.org/packages/reason-react-ppx/) and add `(preprocess (pps reason-react-ppx))` in [`melange.emit or library`](https://dune.readthedocs.io/en/stable/melange.html) stanzas in your `dune` file.

Here's a list of transformations made by the [ppx](https://ocaml.org/docs/metaprogramming):
# What the ppx does

Here's a list of transformations made by the [ppx](https://ocaml.org/docs/metaprogramming).

## Uncapitalized

Expand All @@ -17,27 +25,26 @@ Here's a list of transformations made by the [ppx](https://ocaml.org/docs/metapr
transforms into

```reason
ReactDOM.createDOMElementVariadic(
ReactDOM.jsxs(
"div",
~props=ReactDOM.domProps(~foo=bar, ()),
[|child1, child2|]
);
ReactDOM.domProps(
~children=React.array([|child1, child2|]),
~foo=bar,
(),
)
)
```

which compiles to the JavaScript code:

```js
React.createElement('div', {foo: bar}, child1, child2)
React.jsx('div', {foo: bar, children: [ child1, child2 ] })
```

Prop-less `<div />` transforms into

```reason
ReactDOM.createDOMElementVariadic(
"div",
~props=ReactDOM.domProps(),
[||]
);
ReactDOM.jsx("div", ReactDOM.domProps());
```

Which compiles to
Expand All @@ -49,80 +56,85 @@ React.createElement('div', {})
## Capitalized

```reason
<MyReasonComponent key={a} ref={b} foo={bar} baz={qux}> {child1} {child2} </MyReasonComponent>
<MyReasonComponent ref={b} foo={bar} baz={qux}> {child1} {child2} </MyReasonComponent>
```

transforms into

```reason
React.createElementVariadic(
React.jsxs(
MyReasonComponent.make,
MyReasonComponent.makeProps(
~key=a,
~ref=b,
~foo=bar,
~baz=qux,
~children=React.null,
~children=[|child1, child2|],
()
),
[|child1, child2|]
);
```

which compiles to

```js
React.createElement(
React.jsxs(
MyReasonComponent.make,
{
key: a,
ref: b,
foo: bar,
baz: qux,
children: null,
children: [ child1, child2 ],
},
child1,
child2,
);
```

Prop-less `<MyReasonComponent />` transforms into

```reason
React.createElement(MyReasonComponent.make, MyReasonComponent.makeProps());
React.jsx(
MyReasonComponent.make,
MyReasonComponent.makeProps(),
);
```

which compiles to

```js
React.createElement(MyReasonComponent.make, {});
React.jsx(MyReasonComponent.make, {});
```

The `make` above is exactly the same `make` function you've seen in the previous section.

`ref` and `key` are reserved in ReasonReact, just like in ReactJS. **Don't** use them as props in your component!
`ref` and `key` are reserved in reason-react, just like in ReactJS. **Don't** use them as props in your component!

## Fragment

Fragment lets you group elements without a wrapper node, and return a single element without any effect on the DOM. More details about this in the [react documentation: Fragments](https://react.dev/reference/react/Fragment).

The empty JSX tag `<></>` is shorthand for `<React.Fragment></React.Fragment>`

```reason
<> child1 child2 </>;
```

transforms into

```reason
ReactDOMRe.createElement(ReasonReact.fragment, [|child1, child2|]);
React.jsx(
React.jsxFragment,
ReactDOM.domProps(~children=React.array([|child1, child2|]), ()),
);
```

Which compiles to

```js
React.createElement(React.Fragment, undefined, child1, child2);
React.jsx(React.Fragment, { children: [child1, child2] });
```

## Children

ReasonReact children are **fully typed**, and you can pass any data structure to it (as long as the receiver component permits it). When you write:
reason-react children are **fully typed**, and you can pass any data structure to it (as long as the receiver component permits it). When you write:

```reason
<MyReasonComponent> <div /> <div /> </MyReasonComponent>
Expand Down
11 changes: 3 additions & 8 deletions dune-project
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,10 @@
(name reason-react)
(synopsis "Reason bindings for React.js")
(description
"ReasonReact helps you use Reason to build React components with deeply integrated, strong, static type safety.\n\nIt is designed and built by people using Reason and React in large, mission critical production React codebases.")
"reason-react helps you use Reason to build React components with deeply integrated, strong, static type safety.\n\nIt is designed and built by people using Reason and React in large, mission critical production React codebases.")
(depends
ocaml
(melange
(or
(>= 3.0.0)
(and
(<= 5.1.0-53)
:with-test)))
(melange (<= 5.1.0))
(reason-react-ppx
(= :version))
(reason
Expand All @@ -57,7 +52,7 @@
(package
(name reason-react-ppx)
(synopsis "React.js JSX PPX")
(description "ReasonReact JSX PPX")
(description "reason-react JSX PPX")
(depends
(ocaml
(>= 4.14))
Expand Down
21 changes: 10 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 3 additions & 18 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,22 +1,7 @@
{
"name": "reason-react",
"version": "0.11.0",
"description": "React bindings for Reason",
"files": [
"dune",
"dune-project",
"README.md",
"HISTORY.md",
"LICENSE",
"src",
"ppx/src",
"reason-react-ppx.opam",
"reason-react.opam"
],
"keywords": [
"reasonml",
"react"
],
"version": "0.0.0",
"description": "This package.json is used to install node development dependencies",
"author": "",
"license": "MIT",
"repository": {
Expand All @@ -26,7 +11,7 @@
"homepage": "https://reasonml.github.io/reason-react/",
"devDependencies": {
"@testing-library/dom": "^10.4.0",
"@testing-library/react": "^16.0.1",
"@testing-library/react": "^16.3.0",
"http-server": "^14.1.1",
"jest": "^26.0.1",
"react": "^19.1.0",
Expand Down
2 changes: 1 addition & 1 deletion reason-react-ppx.opam
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# This file is generated by dune, edit dune-project instead
opam-version: "2.0"
synopsis: "React.js JSX PPX"
description: "ReasonReact JSX PPX"
description: "reason-react JSX PPX"
maintainer: [
"David Sancho <[email protected]>"
"Antonio Monteiro <[email protected]>"
Expand Down
Loading
Loading