I’m new to Elm and TEA, and from what I’ve seen, stateful components are discouraged here. Even the state of reusable views (borrowing the terminology from the elm-sortable-table
package) is stored in the caller’s model. However, I haven’t been able to find a clear explanation listing the concrete benefits of this approach.
Examples make for better questions, so for that, I’ll use the aforementioned elm-sortable-table
package. In its documentation, it says:
The data displayed in the table is given as an argument to
view
. To put that another way, theTable.State
value only tracks the details specific to displaying a sorted table, not the actual data to appear in the table.
That makes sense to me. What doesn’t is why the “details specific to displaying” the table need to be stored by the caller. As far as I’m concerned, those are implementation details. The caller doesn’t care about the table’s internal state any more than a comment box cares about the cursor position of its <textarea>
—or the cursor’s opacity, if it’s blinking. And the <textarea>
doesn’t care about the browser’s text renderer, which in turn doesn’t care about the internal state of its text shaper; so on and so forth.
To begin with, Elm uses stateful components as its building blocks. That’s what all HTML elements are. Yet, it appears to me that a line has been drawn between browser-space and user-space components. Why? What makes a tree view, a combo box, or even reimplementations of ugly and difficult-to-style elements different from the browser’s built-in elements?
Let’s use Notion as another example. The app has a sidebar which lists your pages in a tree view. If I were building this, my first instinct would be to shop around for a tree view component. I could import it as, say, a Web Component and use it happily. That’s a valid way to write an Elm app, right? On the other hand, if none of the off-the-shelf libraries were satisfactory and I decided to implement it manually in Elm (or if the library were written in Elm), I would end up storing its state in my model. What does this accomplish that the Web Component approach didn’t?
The most compelling reason I could find is that state you don’t own is state you will lose if the component is destroyed. That’s definitely a good argument. Are there more?
My hope is that understanding the rationale behind this advice (or, dare I say, dogma) will give me a heuristic I can use to determine which parts of my UI should be written as Elm prescribes and which should be made into components/widgets when using TEA-style frameworks that do support both (such as iced).