What’s the state of the art for implementing the Functional Core, Imperative Shell approach in ClojureScript (or Squint / Cherry) frontends?
In React, it’s hard. Functional components seem like pure functions, but as soon as you introduce state (via useState
or a state management library), they’re not. Their result is no longer the result of their props (arguments); you have to peek at the implementation to see what state it might be subscribing to.
You can separate things out into stateful components that delegate to pure presentational components. However state can be infectious. Someone introduces a wee bit of state to primitive component and boom, all previously pure components that delegate to that component directly or indirectly are now impure.
Plus, separating into pure vs stateful components is more boiler plate that developers tend to avoid. Hooks are so easy to use that they tend to encourage throwing a little state directly into a previously pure component. Maybe that’s wrong, but keeping things pure feels like swimming upstream.
UIx and similar libraries that embrace React are great, but would seem to have the same issue.
I’ve been peeking at Reagent, and while it seems very elegant, as soon as you use a stateful atom in a component, it’s no longer pure; similarly if subscribing to a query in Reframe. I guess this is not surprising since Reagent is React under the hood. The fundamental building blocks of React are components, and React components are stateful with a lifecycle. They’re not pure functions (appearances to the contrary).
Prop drilling is a solution for small clusters of components, but that doesn’t scale very well.
Is there a solution for this problem? Is React the problem, SPAs in general, or something else?
The best I’ve been able to come up with so far is to aggressively extract out pure functions wherever, using TDD to guide: if mocking is hard maybe that’s an opportunity to pull stuff out into more easily testable pure functions. But it’s a slog.