Well, I wanted to see what all the noise was about regarding signals but the options for integrating into ReScript seemed sparse.
There are the issues with SolidJS that have been discussed in other posts. I tried to use the existing bindings but I couldn’t get it working with v11 (and I really wasn’t keen on adding Babel anyway).
I saw that some people were using Preact by aliasing React to Preact, but the question remained as to whether you could use Preact signals (although I would guess not in that fashion as React doesn’t have a signals library that could be aliased).
The I saw that Preact has a library that allows you to integrate signals into React. I really wanted to get a handle on creating bindings so I thought this would be good practice.
Obviously my example will be pretty much a toy app and I can’t speak for how useful (or useless) signals are in React, but just figured I’d share my starter set of bindings. I opted for the hooks integration instead of the Babel transform integration. Preact recommends the Babel transform method, but I figured creating bindings is challenging enough with having to worry about adding Babel config drama.
Preact.res:
module Signal = {
type t
@module("@preact/signals-react") @new external make: 'value => t = "Signal"
@get external getValue: t => 'value = "value"
@set external setValue: (t, 'value) => unit = "value"
}
module EffectStore = {
type t
}
@module("@preact/signals-react") external createSignal: 'value => Signal.t = "signal"
@module("@preact/signals-react") external useSignal: 'value => Signal.t = "useSignal"
@module("@preact/signals-react/runtime") external useSignals: unit => EffectStore.t = "useSignals"
App.res:
external asInterval: int => intervalId = "%identity"
let counter = Preact.createSignal(0)
let intervalId = ref(asInterval(0))
@react.component
let make = () => {
let _ = Preact.useSignals()
let preactCount = Preact.useSignal(0)
let (count, setCount) = React.useState(() => 0)
let {getValue, setValue} = module(Preact.Signal)
let startCounter = () => {
intervalId.contents = setInterval(() => {
counter->setValue(counter->getValue + 1)
}, 1000)
}
let stopCounter = () => {
clearInterval(intervalId.contents)
}
<div className="p-6">
<h1 className="text-3xl font-semibold"> {"What is this about?"->React.string} </h1>
<p>
{React.string("This is a simple template for a Vite project using ReScript & Tailwind CSS.")}
</p>
<h2 className="text-2xl font-semibold mt-5"> {React.string("Fast Refresh Test")} </h2>
<Button onClick={_ => setCount(count => count + 1)}>
{React.string(`React count is ${count->Int.toString}`)}
</Button>
<Button onClick={_ => preactCount->setValue(preactCount->getValue + 1)}>
{React.string(`Preact signals-react count is ${preactCount->getValue->Int.toString}`)}
</Button>
<p>
{React.string("Edit ")}
<code> {React.string("src/App.res")} </code>
{React.string(" and save to test Fast Refresh.")}
</p>
<p> {React.string(`preactCount is ${preactCount->getValue}`)} </p>
<div>
<Button onClick={_ => startCounter()}> {React.string("Start Counter")} </Button>
<Button onClick={_ => stopCounter()}> {React.string("Stop Counter")} </Button>
</div>
<p> {React.string(`The counter is ${counter->getValue}`)} </p>
</div>
}
Again, I’m no expert on Preact, the signals vs hooks debate, Solid vs React debate, and definitely not on bindings. This is just something I wanted to do so I could play around with signals and also try to get a better understanding of creating bindings. The Preact documentation will be your best resource if you want to understand why they believe signals in React can be beneficial.