Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
4d9eeca
Add useTransition with async support
davesnx Jul 16, 2024
39189e0
Add useTransitionAsync into the interface
davesnx Jul 16, 2024
b869bd3
Add useOptimistic
davesnx Jul 16, 2024
e47a0ca
Rename use to usePromise and add useContext
davesnx Jul 16, 2024
81942e4
Move useTransitionAsync to Experimental
davesnx Jul 16, 2024
b823e5c
Add formStatus to interface
davesnx Jul 16, 2024
c4a7fdd
Leftover from removing useTransitionAsync to Experimental
davesnx Jul 16, 2024
fd7faa4
Add action_ and action_Async in ReactDOM props
davesnx Jul 16, 2024
97dd3d3
Fix reference to function on formStatus
davesnx Jul 16, 2024
e56f547
Merge branch 'main' of github.com:/reasonml/reason-react into 19
davesnx Jul 17, 2024
06b1da6
Embed FormData for now
davesnx Jul 17, 2024
9031415
Add test of Form with useOptimistic
davesnx Jul 17, 2024
52c8144
Merge branch 'main' of github.com:/reasonml/reason-react into 19
davesnx Jul 17, 2024
05d9f44
Merge branch 'main' of github.com:/reasonml/reason-react into 19
davesnx Nov 15, 2024
2190bb9
Embed FormData into ReactDOM
davesnx Nov 18, 2024
e3a97dd
Move formStatus into ReactDOM
davesnx Nov 18, 2024
ea1ff9a
Run formatter
davesnx Nov 18, 2024
a1cbb4f
Bind React.useActionState instead of ReactDOM.useFormState
davesnx Nov 18, 2024
1ad8321
Remove React.use being 'a => 'b
davesnx Nov 18, 2024
447ca53
Revert change on ReactDOM's prop 'action'
davesnx Nov 18, 2024
50bde6a
useAction state published in React.rei
davesnx Nov 18, 2024
16090ac
Remove React.use being 'a => 'b
davesnx Nov 18, 2024
e6fdb2e
Use act from 'react' inseat of react-dom/test-utils
davesnx Nov 18, 2024
ca13b5a
Snapshot with lower {}
davesnx Nov 20, 2024
563d8af
Update src/React.re
davesnx Nov 20, 2024
9ce19ea
Update src/React.re
davesnx Nov 20, 2024
5636b99
Update src/React.re
davesnx Nov 20, 2024
cb48b76
Add uri comment back on action
davesnx Nov 25, 2024
e78adcc
Add deprecations on ReactDOMTestUtils
davesnx Nov 25, 2024
f5f5579
Merge branch '19' of github.com:/reasonml/reason-react into 19
davesnx Nov 25, 2024
66cd920
Replace react dom's testing library with ReactTestingLibrary (#859)
davesnx Nov 25, 2024
08f5e19
Enable ref as valid prop (#862)
davesnx Nov 25, 2024
ea1f768
Merge branch 'main' of github.com:/reasonml/reason-react into 19
davesnx Nov 25, 2024
05ecc63
Merge branch '19' of github.com:/reasonml/reason-react into 19
davesnx Nov 25, 2024
e017f0b
Migrate custom childrens test to RTL
davesnx Nov 25, 2024
ba36dc2
Fix role for React__test
davesnx Nov 25, 2024
52e585a
Rollback change on _ppx
davesnx Nov 25, 2024
4c0e525
Merge branch 'main' of github.com:/reasonml/reason-react into 19
davesnx Feb 24, 2025
0bc3400
Install latest react version with the useState fix
davesnx Feb 24, 2025
e9a07d7
Merge branch 'main' of github.com:/reasonml/reason-react into 19
davesnx Feb 26, 2025
35f55f2
Merge branch 'main' of github.com:/reasonml/reason-react into 19
davesnx Apr 3, 2025
7cf0290
Use React@19.1.0
davesnx Apr 3, 2025
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
15 changes: 14 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ jest: ## Run the jest unit tests
jest-watch: ## Run the jest unit tests in watch mode
@npx jest --watch

.PHONY: jest-devtools
jest-devtools: ## Run the jest unit tests in watch mode
@echo "open Chrome and go to chrome://inspect"
@node --inspect-brk node_modules/.bin/jest --runInBand --detectOpenHandles

.PHONY: test
test: ## Run the runtests from dune (snapshot)
@$(DUNE) build @runtest
Expand All @@ -54,11 +59,19 @@ format-check: ## Checks if format is correct
.PHONY: install
install: ## Update the package dependencies when new deps are added to dune-project
@opam install . --deps-only --with-test --with-dev-setup
@npm install
@npm install --force

.PHONY: init
create-switch: ## Create a local opam switch
@opam switch create . 5.2.0 --no-install

.PHONY: init
init: create-switch install ## Create a local opam switch, install deps

.PHONY: demo-watch
demo-watch: ## Build the demo in watch mode
@$(DUNE) build @melange-app --watch

.PHONY: demo-serve
demo-serve: ## Build the demo and serve it
npx http-server -p 8080 _build/default/demo/
9 changes: 9 additions & 0 deletions demo/dune
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
(melange.emit
(target demo)
(alias melange-app)
(module_systems
(es6 mjs))
(libraries reason-react melange.belt melange.dom)
(runtime_deps index.html)
(preprocess
(pps melange.ppx reason-react-ppx)))
42 changes: 42 additions & 0 deletions demo/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!DOCTYPE html>
<html lang="en">

<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Demo reason-react</title>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/yegor256/tacit@gh-pages/tacit-css-1.8.1.min.css" />
<style>
body {
padding: 2rem;
}

#root {
margin-left: auto;
margin-right: auto;
width: 900px;
}
</style>
<script type="importmap">
{
"imports": {
"melange/": "./demo/node_modules/melange/",
"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"
}
}
</script>
</head>

<body>
<div id="root"></div>
</body>
<script type="module" src="./demo/demo/main.mjs"></script>

</html>
187 changes: 187 additions & 0 deletions demo/main.re
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
module Stateful = {
[@react.component]
let make = (~title, ~initialValue=0, ~children=React.null) => {
let (value, setValue) = React.useState(() => initialValue);
let onClick = _ => setValue(value => value + 1);

<section>
<h3> {React.string(title)} </h3>
<button key="asdf" onClick> value->React.int </button>
children
</section>;
};
};

module Reducer = {
type action =
| Increment
| Decrement;

[@react.component]
let make = (~initialValue=0) => {
let (state, send) =
React.useReducer(
(state, action) =>
switch (action) {
| Increment => state + 1
| Decrement => state - 1
},
initialValue,
);

Js.log2("Reducer state", state);

<section>
<h3> {React.string("React.useReducer")} </h3>
<main> state->React.int </main>
<button onClick={_ => send(Increment)}>
"Increment"->React.string
</button>
<button onClick={_ => send(Decrement)}>
"Decrement"->React.string
</button>
</section>;
};
};

module ReducerWithMapState = {
type action =
| Increment
| Decrement;

[@react.component]
let make = (~initialValue=0) => {
let (state, send) =
React.useReducerWithMapState(
(state, action) =>
switch (action) {
| Increment => state + 1
| Decrement => state - 1
},
initialValue,
initialValue => initialValue + 75,
);

Js.log2("ReducerWithMapState state", state);

<section>
<h3> {React.string("React.useReducerWithMapState")} </h3>
<main> state->React.int </main>
<button onClick={_ => send(Increment)}>
"Increment"->React.string
</button>
<button onClick={_ => send(Decrement)}>
"Decrement"->React.string
</button>
</section>;
};
};

module WithEffect = {
[@react.component]
let make = (~value) => {
React.useEffect1(
() => {
Js.log("useEffect");
None;
},
[|value|],
);

React.string("React.useEffect");
};
};

module RerenderOnEachClick = {
[@react.component]
let make = (~value=0, ~callback as _) => {
let (value, setValue) = React.useState(() => value);
let onClick = _ =>
if (value < 3) {
Js.log2("Clicked with:", value);
setValue(value => value + 1);
} else {
Js.log("Max value reached, not firing a rerender");
setValue(value => value);
};

<section>
<h3> {React.string("RerenderOnEachClick")} </h3>
<button onClick> <WithEffect value /> </button>
</section>;
};
};

module WithLayoutEffect = {
[@react.component]
let make = (~value=0, ~callback) => {
React.useLayoutEffect1(
() => {
callback(value);
Js.log("useLayoutEffect");
None;
},
[|value|],
);

<section> <h3> {React.string("React.useLayoutEffect")} </h3> </section>;
};
};

module WithRefAndEffect = {
[@react.component]
let make = (~callback) => {
let myRef = React.useRef(1);
React.useEffect0(() => {
myRef.current = myRef.current + 1;
callback(myRef);
None;
});

<section>
<h3> {React.string("React.useRef and useEffect")} </h3>
<main> {React.int(myRef.current)} </main>
</section>;
};
};

[@mel.module "react"]
external useReducer:
([@mel.uncurry] (('state, 'action) => 'state), 'state) =>
('state, 'action => unit) =
"useReducer";

module UseReducerNoProblemo = {
[@react.component]
let make = () => {
let reducer = (v, _) => v + 1;
let (state, send) = useReducer(reducer, 0);
Js.log("asdfasd");
<button onClick={_ => send(0)}> {React.int(state)} </button>;
};
};

module App = {
[@react.component]
let make = (~initialValue) => {
let value = 99;
let callback = _number => ();

<main>
<Stateful title="Stateful" initialValue />
<Reducer key="reducer" initialValue />
<ReducerWithMapState key="reducer-with-map-state" initialValue />
<RerenderOnEachClick key="rerender-on-each-click" value=0 callback />
<WithLayoutEffect key="layout-effect" value callback />
<WithRefAndEffect key="ref-and-effect" callback />
<UseReducerNoProblemo />
</main>;
};
};

switch (ReactDOM.querySelector("#root")) {
| Some(el) =>
let root = ReactDOM.Client.createRoot(el);
ReactDOM.Client.render(root, <App initialValue=0 />);
| None => Js.log("No root element found")
};
2 changes: 1 addition & 1 deletion dune
Original file line number Diff line number Diff line change
@@ -1 +1 @@
(dirs src test ppx)
(dirs src test ppx demo)
Loading