diff --git a/docs/jsx.md b/docs/jsx.md index caf80474a..e562c91fc 100644 --- a/docs/jsx.md +++ b/docs/jsx.md @@ -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 @@ -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 `
` transforms into ```reason -ReactDOM.createDOMElementVariadic( - "div", - ~props=ReactDOM.domProps(), - [||] -); +ReactDOM.jsx("div", ReactDOM.domProps()); ``` Which compiles to @@ -49,61 +56,63 @@ React.createElement('div', {}) ## Capitalized ```reason - {child1} {child2} + {child1} {child2} ``` 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 `` 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 `` + ```reason <> child1 child2 ; ``` @@ -111,18 +120,21 @@ The `make` above is exactly the same `make` function you've seen in the previous 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
diff --git a/dune-project b/dune-project index 98b0a95fa..0bea373be 100644 --- a/dune-project +++ b/dune-project @@ -31,7 +31,7 @@ (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 (>= 3.0.0)) @@ -53,7 +53,7 @@ (package (name reason-react-ppx) (synopsis "React.js JSX PPX") - (description "ReasonReact JSX PPX") + (description "reason-react JSX PPX") (depends (ocaml (>= 4.14)) diff --git a/reason-react-ppx.opam b/reason-react-ppx.opam index 8bbc1290c..b827c1ed0 100644 --- a/reason-react-ppx.opam +++ b/reason-react-ppx.opam @@ -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 " "Antonio Monteiro " diff --git a/reason-react.opam b/reason-react.opam index c7b0c6d55..28eff6fbc 100644 --- a/reason-react.opam +++ b/reason-react.opam @@ -2,7 +2,7 @@ opam-version: "2.0" synopsis: "Reason bindings for React.js" description: """ -ReasonReact helps you use Reason to build React components with deeply integrated, strong, static type safety. +reason-react helps you use Reason to build React components with deeply integrated, strong, static type safety. It is designed and built by people using Reason and React in large, mission critical production React codebases.""" maintainer: [ diff --git a/src/React.re b/src/React.re index ae8cd326e..289044551 100644 --- a/src/React.re +++ b/src/React.re @@ -723,7 +723,9 @@ external useContext: Context.t('any) => 'any = "useContext"; [@mel.module "react"] external useRef: 'value => ref('value) = "useRef"; [@mel.module "react"] external useId: unit => string = "useId"; -[@mel.module "react"] external useDeferredValue: 'a => 'a = "useDeferredValue"; +[@mel.module "react"] +external useDeferredValue: ('a, ~initialValue: 'a=?) => 'a = + "useDeferredValue"; [@mel.module "react"] external useImperativeHandle0: @@ -877,6 +879,11 @@ module Uncurried = { external useTransition: unit => (bool, callback(callback(unit, unit), unit)) = "useTransition"; +[@mel.module "react"] +external useTransitionAsync: + unit => (bool, callbackAsync(callback(unit, unit), unit)) = + "useTransition"; + [@mel.module "react"] external startTransition: ([@mel.uncurry] (unit => unit)) => unit = "startTransition"; @@ -887,12 +894,15 @@ external useDebugValue: ('value, ~format: 'value => string=?, unit) => unit = [@mel.module "react"] external act: (unit => unit) => Js.Promise.t(unit) = "act"; + [@mel.module "react"] external actAsync: (unit => Js.Promise.t(unit)) => Js.Promise.t(unit) = "act"; module Experimental = { /* This module is used to bind to APIs for future versions of React. There is no guarantee of backwards compatibility or stability. */ + external promise: Js.Promise.t(element) => element = "%identity"; + /* https://react.dev/reference/react/use */ [@mel.module "react"] external usePromise: Js.Promise.t('a) => 'a = "use"; [@mel.module "react"] external useContext: Context.t('a) => 'a = "use"; diff --git a/src/React.rei b/src/React.rei index a2bcefb0e..29e5c63f5 100644 --- a/src/React.rei +++ b/src/React.rei @@ -415,7 +415,9 @@ external useContext: Context.t('any) => 'any = "useContext"; [@mel.module "react"] external useRef: 'value => ref('value) = "useRef"; [@mel.module "react"] external useId: unit => string = "useId"; -[@mel.module "react"] external useDeferredValue: 'a => 'a = "useDeferredValue"; +[@mel.module "react"] +external useDeferredValue: ('a, ~initialValue: 'a=?) => 'a = + "useDeferredValue"; [@mel.module "react"] external useImperativeHandle0: @@ -573,14 +575,22 @@ external startTransition: ([@mel.uncurry] (unit => unit)) => unit = external useTransition: unit => (bool, callback(callback(unit, unit), unit)) = "useTransition"; +[@mel.module "react"] +external useTransitionAsync: + unit => (bool, callbackAsync(callback(unit, unit), unit)) = + "useTransition"; + [@mel.module "react"] external act: (unit => unit) => Js.Promise.t(unit) = "act"; + [@mel.module "react"] external actAsync: (unit => Js.Promise.t(unit)) => Js.Promise.t(unit) = "act"; module Experimental: { /* This module is used to bind to APIs for future versions of React. There is no guarantee of backwards compatibility or stability. */ + external promise: Js.Promise.t(element) => element = "%identity"; + [@mel.module "react"] external usePromise: Js.Promise.t('a) => 'a = "use"; [@mel.module "react"] external useContext: Context.t('a) => 'a = "use";