I’m working with Preact’s signals in ReScript and I’m implementing a lightweight Finite State Machine using variants. I’m trying to implement a transitionSignal so that components can subscribe to transitions to trigger effects or react to various state changes.
let transitionSignal: Signal.t<transition> = Signal.computed(() => {
let action = actionSignal->Signal.get
let nextState = stateSignal->Signal.get
let {nextState: prevState} = transitionSignal->Signal.peek
{next: nextState, prev: prevState, action}
})
The problem is that rescript does not like let {nextState: prevState} = transitionSignal->Signal.peek
due to it not being defined yet. I’ve tried adding let rec ...
but that doesn’t work either as the compiler throws a "This kind of expression is not allowed as right-hand side of let rec"
error.
Any suggestions for what can be done to make that work? I could have a private signal for the last state change but that is suboptimal.
1 Like
I’m not very familiar with Preact Signals, but I’m quite surprised that it allows this kind of recursive referencing.
Is this a common case? Can you give me an expanded example in JavaScript?
1 Like
My mistake. Implemented a JS equivalent example but the signals library will throw
Error: Cycle detected
Even if you use signal.peek()
in an untracked
block, it will still throw that error. Looks like Preact’s signals are just not intended to work that way, and looking at their issues seems the recommended path is to implement a function that updates the signal outside of itself.
Fortunately, I did shift directions last night and found a better way to structure it. tasky/frontend/src/State.res at cd718aaa51577d8e7b31a221c34a0e45685b4516 · jaidetree/tasky · GitHub
In short…
- Defined my action signal globally at the top and all the actions across multiple FSMs.
- The root FSM actions wrap the actions for subfsms so I can dispatch
NewTask(Create)
to dispatch the Create action only to the NewTask FSM.
- In the root FSM implemented an effect that reacts to actions by reading the state signal, calculating the new state with a reduction, and updates the state signal and the transition signal in a batch.
The downside of this approach is that the actions are defined outside of their FSMs, but the upside is that sub FSMs can dispatch effectful actions through the root FSM.
Anyway, that was a good question which helped me discover the baked in limitations of Preact’s signals. Thanks!
4 Likes
Often, facing the expressiveness limits of ReScript is a signal that I’m going to wrong way 
2 Likes