Skip to content

Commit

Permalink
Merge branch 'main' into feat/add-startTransition
Browse files Browse the repository at this point in the history
  • Loading branch information
davesnx authored Jul 17, 2024
2 parents 37839ff + 88a4fde commit 1c589a9
Show file tree
Hide file tree
Showing 7 changed files with 86 additions and 44 deletions.
7 changes: 7 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
# Unreleased

* Convert `ReasonReactErrorBoundary` to Reason instead of `%raw` JS. This has
the benefit of skipping a hardcoded `require('react')` call (@anmonteiro in
[#839](https://github.com/reasonml/reason-react/pull/839))


# 0.14.1

* Support JSX transform with fragments (@tatchi in
Expand Down
6 changes: 3 additions & 3 deletions docs/installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,13 @@ The `.re`/`.ml` files compile to straightforward `.js` files inside your `_build
git clone https://github.com/melange-re/melange-opam-template my-reason-react-app

# This will initialise the opam switch and install all the dependencies (from both opam and npm)
cd my-reason-react-app && make init
cd my-reason-react-app && npm run init
# We install native dependencies (melange, dune, reason and reason-react) from opam
# while JavaScript dependencies (react, react-dom, webpack) from npm

# In separate terminals:
make watch # It will watch for changes in your Reason/OCaml files and compile them to JavaScript
make serve # Serves the application with a local HTTP server
npm run watch # It will watch for changes in your Reason/OCaml files and compile them to JavaScript
npm run serve # Serves the application with a local HTTP server
```

Read more about the template in the [opam-template README](https://github.com/melange-re/melange-opam-template).
Expand Down
14 changes: 7 additions & 7 deletions flake.lock

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

2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
};
# Due to a Reason version mismatch, the generated OCaml PPX diff
# looks different
doCheck = true;
doCheck = false;
checkInputs = [ ];
checkPhase = "dune build @runtest -p reason-react,reason-react-ppx";
nativeCheckInputs = [ reason merlin pkgs.jq ];
Expand Down
19 changes: 13 additions & 6 deletions src/React.re
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,9 @@ external component: componentLike('props, element) => component('props) =
external createElement: (component('props), 'props) => element =
"createElement";

[@mel.module "react"]
external isValidElement: element => bool = "isValidElement";

[@mel.module "react"]
external cloneElement: (element, 'props) => element = "cloneElement";

Expand Down Expand Up @@ -464,6 +467,9 @@ external displayName: component('props) => option(string) = "displayName";

/* HOOKS */

/* This is used as return values */
type callback('input, 'output) = 'input => 'output;

/*
* Yeah, we know this api isn't great. tl;dr: useReducer instead.
* It's because useState can take functions or non-function values and treats
Expand All @@ -488,13 +494,13 @@ external useReducerWithMapState:
'initialState,
[@mel.uncurry] ('initialState => 'state)
) =>
('state, 'action => unit) =
('state, callback('action, unit)) =
"useReducer";

[@mel.module "react"]
external useSyncExternalStore:
(
~subscribe: ([@mel.uncurry] (unit => unit)) => [@mel.uncurry] (unit => unit),
~subscribe: (unit => unit) => callback(unit, unit),
~getSnapshot: unit => 'snapshot
) =>
'snapshot =
Expand All @@ -503,7 +509,7 @@ external useSyncExternalStore:
[@mel.module "react"]
external useSyncExternalStoreWithServer:
(
~subscribe: ([@mel.uncurry] (unit => unit)) => [@mel.uncurry] (unit => unit),
~subscribe: (unit => unit) => callback(unit, unit),
~getSnapshot: unit => 'snapshot,
~getServerSnapshot: [@mel.uncurry] (unit => 'snapshot)
) =>
Expand Down Expand Up @@ -866,14 +872,15 @@ module Uncurried = {
"useCallback";
};

[@mel.module "react"]
external startTransition: ([@mel.uncurry] (unit => unit)) => unit = "startTransition";

type callback('input, 'output) = 'input => 'output;

[@mel.module "react"]
external useTransition: unit => (bool, callback(callback(unit, unit), unit)) =
"useTransition";

[@mel.module "react"]
external startTransition: ([@mel.uncurry] (unit => unit)) => unit = "startTransition";

[@mel.module "react"]
external useDebugValue: ('value, ~format: 'value => string=?, unit) => unit =
"useDebugValue";
Expand Down
13 changes: 8 additions & 5 deletions src/React.rei
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ external component: componentLike('props, element) => component('props) =
external createElement: (component('props), 'props) => element =
"createElement";

[@mel.module "react"]
external isValidElement: element => bool = "isValidElement";

[@mel.module "react"]
external cloneElement: (element, 'props) => element = "cloneElement";

Expand Down Expand Up @@ -183,10 +186,13 @@ external useReducerWithMapState:
('state, 'action => unit) =
"useReducer";

/* This is used as return values */
type callback('input, 'output) = 'input => 'output;

[@mel.module "react"]
external useSyncExternalStore:
(
~subscribe: ([@mel.uncurry] (unit => unit)) => [@mel.uncurry] (unit => unit),
~subscribe: (unit => unit) => callback(unit, unit),
~getSnapshot: unit => 'snapshot
) =>
'snapshot =
Expand All @@ -195,7 +201,7 @@ external useSyncExternalStore:
[@mel.module "react"]
external useSyncExternalStoreWithServer:
(
~subscribe: ([@mel.uncurry] (unit => unit)) => [@mel.uncurry] (unit => unit),
~subscribe: (unit => unit) => callback(unit, unit),
~getSnapshot: unit => 'snapshot,
~getServerSnapshot: [@mel.uncurry] (unit => 'snapshot)
) =>
Expand Down Expand Up @@ -382,9 +388,6 @@ external useMemo7:
([@mel.uncurry] (unit => 'any), ('a, 'b, 'c, 'd, 'e, 'f, 'g)) => 'any =
"useMemo";

/* This is used as return values */
type callback('input, 'output) = 'input => 'output;

[@mel.module "react"] external useCallback: 'fn => 'fn = "useCallback";
[@mel.module "react"]
external useCallback0: ('fn, [@mel.as {json|[]|json}] _) => 'fn =
Expand Down
69 changes: 47 additions & 22 deletions src/ReasonReactErrorBoundary.re
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,57 @@ type params('error) = {
info,
};

[%%mel.raw
{|
var React = require("react");
var ErrorBoundary = (function (Component) {
function ErrorBoundary(props) {
Component.call(this);
this.state = {error: undefined};
};
ErrorBoundary.prototype = Object.create(Component.prototype);
ErrorBoundary.prototype.componentDidCatch = function(error, info) {
this.setState({error: {error: error, info: info}});
};
ErrorBoundary.prototype.render = function() {
return this.state.error != undefined
? this.props.fallback(this.state.error)
: this.props.children
};
return ErrorBoundary;
})(React.Component);
|}
];
[@mel.scope "Object"] external objCreate: 'a => Js.t({..}) = "create";

type reactComponentClass;

[@mel.module "react"] external component: reactComponentClass = "Component";
[@mel.send] external componentCall: (reactComponentClass, _) => unit = "call";

type componentPrototype;
[@mel.get]
external componentPrototype: reactComponentClass => componentPrototype =
"prototype";

let errorBoundary =
[@mel.this]
(
(self, _props) => {
componentCall(component, self);
self##state #= {"error": Js.undefined};
}
);

[@mel.set] external setPrototype: (_, _) => unit = "prototype";
setPrototype(errorBoundary, objCreate(componentPrototype(component)));

[@mel.set] [@mel.scope "prototype"]
external setComponentDidCatch:
(_, [@mel.this] (('self, 'error, 'info) => unit)) => unit =
"componentDidCatch";

setComponentDidCatch(errorBoundary, [@mel.this] (self, error, info) => {
self##setState({
"error": {
error,
info,
},
})
});

[@mel.set] [@mel.scope "prototype"]
external setRender: (_, [@mel.this] ('self => unit)) => unit = "render";
setRender(errorBoundary, [@mel.this] self => {
switch (Js.Undefined.testAny(self##state##error)) {
| false => self##props##fallback(self##state##error)
| true => self##props##children
}
});

[@react.component]
external make:
(~children: React.element, ~fallback: params('error) => React.element) =>
React.element =
"ErrorBoundary";
"errorBoundary";

let make = make;

0 comments on commit 1c589a9

Please sign in to comment.