Brian, thanks for the answer! If Highcharts or other off the shelf component is sufficient, it’s great! Once you declare the configuration, it’s mostly a black box renderer for you. Indeed, building custom charts with similar interactions to my example is more time consuming, though I’m primarily making rather than using them, which explains why we have differing levels of interest in modeling and automating the data dependencies, as well as in composability of glyphs, widgets and charts.
As a minimal example, consider the simplest barchart whose state you can model as {validTime: [0, 1, 2], value: [34.4, 65.3, 98.3]}. It’s straightforward to set it up; it uses a store for this object and Actions can be defined to change the numbers, add or remove bars. For example, AJAX callbacks will issue actions which then result in new values, and then something ensures it gets rerendered (i.e. the new state gets applied to a React render).
However if you want to reuse it as part of a larger view, and maybe use it to show calculated values rather than direct input, you need to refactor its relationship with the store and/or actions. Say, in addition to showing primary input as in the previous example, you also want a barchart to show moving averages based on the primary input. In this case, option A is to keep the store and actions, and make the containing module issue actions (ValueChange etc.) toward the barchart. But with this approach, one ends up with a lot of modules, each having some state, and they issue actions to one another… in some sense, reinventing the FRP inspired paradigm, possibly in a suboptimal way. Option B is to refactor the store; remove the previous object literal (or Action) representation from the store, and ensure that whenever the input (on which the moving average is calculated) changes, the React render is applied to the result of the moving average function. Either way, it doesn’t feel like working with building blocks or a spreadsheet or something like Knime/RapidMiner or shader composition tool. I might overlook patterns too, as most examples (khm.. TodoMVC) are of trivial complexity.
So what I’m trying to learn about FRP alternatives is
- How to move up from one single, atomic component to a structured, multilayered composition of views without tampering with specific component
- Also, performance or other considerations may necessitate that an atomic or larger component is replaced with something different (e.g.WebGL), and in this case, it’s best if changes just pertain to the renderer — the primary thing for my use cases is the complex part, the data flow and its transformations — and renderers should be relatively easy to replace, because I already have representations of the current time domain (in a scrolling chart), the current set of primary or computed time series etc. Even the input and output aren’t bound; WebGL has no touch input, so one captures Canvas or overlaid DOM events and uses inverse scale transformations.
- How to minimize latency between a user or other input action, and the visible result. An extreme case of that is that a new streamed value (e.g. OHLC bar) ends up changing the Y (price) domain in the visible window, and the most minimal response to that is to (a) change the transform CSS style to enlargen the visible price domain and (b) regenerate, if needed, the ticks on the Y axis. Or similar change on panning: when you want ~60FPS animation or ~30FPS on mobile or WebWiew, stuff like not having to reapply the entire state to the entire application view renderer can make a big difference, while less demanding interactions can go the DOM diffing route.
These three criteria worked out rather well with FRP (I used RxJS, Kefir and flyd so far) and as I said I’m learning about potential alternatives like Redux, which also explains my interest when your post stated FRP was not worth it — as I didn’t know your use case, I was seeking the opportunity to get to know more. Maybe it’s just a horses for courses question. There is definitely a commitment price to be paid with FRP as it becomes the primary scaffolding of the project, and debugging, rehydration, time travel, undo/redo etc. take a bit more work.