Fulma icon indicating copy to clipboard operation
Fulma copied to clipboard

Explore converting Fulma.Elmish to using stateful component

Open MangelMaxime opened this issue 6 years ago • 26 comments

When updating the Fulma docs site, I kind of re-discovered the usage of stateful component via Fable.

Using them from Fable, we still gain access to intellisense, compilation checking, etc. Also I would say it's less verbose to write and the output is less verbose too.

From my experience, writing the component in like I initially did for the DatePicker is harder to reason about. Elm is doing it that way because their architecture only provide the support of "stateless" components. But because we use react, we could / should benefit of both worlds.

Because, the Fulma.Elmish components are dedicated to be some kind of "black box" using stateful component could be benefit.

Example of stateful components

@alfonsogarciacaro Any pros / cons ?

@EdouardM I am asking to you too because, I know you wrote one/two components that we will include in the next release :)

MangelMaxime avatar Jan 17 '18 14:01 MangelMaxime

Yes, stateful components are useful to prevent pollution of the global state with tiny things that only affect the UI (like an open box, etc). Just remember you lose debugging, auto-saving, etc, for those things. Also, with latest Fable.React beta you can use tiny Elmish components: they have an API similar to Elmish but translate to React stateful components.

alfonsogarciacaro avatar Jan 17 '18 14:01 alfonsogarciacaro

The component would still be controlled by the caller application via props. We would just use the stateful to manage UI state. I think it should be acceptable if the user experience is better and if it make it easier to maintain.

I will take a look at the "tiny Elmish components" even if I am still not convince by it :)

MangelMaxime avatar Jan 17 '18 14:01 MangelMaxime

Both are very interesting, it's fun you mention that because I wrote a first version of the sortable table but I wasn't very happy of it because state info like sort or which page we are on don't have to be in the way of the developper who only wants to add the component in a view.

I agree that including this information in global state and having it bubble up from the component to the top with elm message passing is adding some noise.

I am going to explore stateful component possibility.

EdouardM avatar Jan 17 '18 15:01 EdouardM

If you want to share your work, please send a PR targeting #93

The structure of the docs changed a bit but you should not be lost. And also, will have access to the latest Fulma API and so we will not have to port it.

MangelMaxime avatar Jan 17 '18 16:01 MangelMaxime

I do not think that reusing stateful components is such a big problem with Elmish if the component to be reused is in a stable production-ready state. They might be blackboxed for Elmish, but if I do a project for someone I care more for those things being present for business logic, networking and prototyping of the actual application I'm about to write and not so much about how a good working, nice looking component handles its visual state internally.

The bottom line for me would be: Do reuse good stable, stateful React components that really work well with Elmish, but don't bother doing with alpha/beta ones 😄. The leverage you can get from a lot of resources that went into existing JavaScript is huge.

@alfonsogarciacaro I really did not get the tiny Elmish concept from a first look. Could you give an example and clarify how this would look in practice?

ghost avatar Jan 31 '18 16:01 ghost

Thanks for your answer @kfrie I still have problems with how react work even if I am using it daily.

Also, in the case of Fulma, we can't really use existing React components because basically there is none having Bulma style + doing the behavior we are expecting from it.

Also, I discover because we use Bulma components, we should also allow users to customize part of the resulting components.

Example:

At work, we are using the DatePicker and we needed to make it bigger via IsLarge I end up using a local version of the component because we don't offer this possibilities by default.

But yes, I agree that in theory we can use either stateless or stateful components with Elmish. We are already doing that for RechartJS or ReactLeaflet for example.

MangelMaxime avatar Jan 31 '18 16:01 MangelMaxime

Hmm true that react components are almost always tied to some specific style. I'm quite new to all this and used semantic-ui-react and react-google-charts so far, so I had no problems with style, but charts don't have custom button, dialog etc, so this could get bad with other components visually.

For Fulma.Elmish components it would be really nice to offer some sort of theme per component basis declared once in some mapping. Is something like that possible? The custom theme would be on top of Bulma I assume.


let myAwesomeTheme = {
 // declaring a theme record
}

let themeConfig = [
  typeof<DatePicker>, myAwesomeTheme 
]

...


|> Program.withThemeConfig themeConfig 

ghost avatar Jan 31 '18 16:01 ghost

Are there any plans to gather a repository of wrapped React components for Fable. Would be really nice if that was offered and maintained at a single point, like DefinitelyTyped for .ts definitions?

ghost avatar Jan 31 '18 16:01 ghost

We already have this kind of repository here

MangelMaxime avatar Jan 31 '18 17:01 MangelMaxime

Ah I know that one! 😄. Just did not notice it was open for such contributions. So I would create Fable.React.GoogleCharts and Fable.React.SemanticUI und src and give them their own Release Notes and send PR?

ghost avatar Jan 31 '18 17:01 ghost

I just stumbled across Cycle.js and its programming model. The way components are defined there do not have the problems discussed here! Is something simliar possible with Elmish in any way?

ghost avatar Jan 31 '18 19:01 ghost

Elmish is not exclusive to React. It's jut the most common renderer we have.

Pure Elmish is just about a loop to manage a state and handle message. It's only render to react when using Elmish.React package. So yes you can you cycles with Elmish if you write the renderer part for it.

If you have a question about Elmish you probably should ask it on the Elmish repo.

MangelMaxime avatar Jan 31 '18 19:01 MangelMaxime

I think cycle.js has its own app lifecycle, so it is more than just a way to reflect virtual DOM. So it is really an alternative programming model. What I think is very special about it, is that Cycle Programs are reusable as components themselves, which is not the case for Elmish:

type Program<'arg, 'model, 'msg, 'view>

Can't use that as part of a larger app as component or can I?

I just came across it and got hooked by the ideas in like 10 minutes. Does anyone of you have working knowledge with Cycle.js and the approach. Would much appreciate some real-world insights.

I placed it here first because it was about components, but I will ask in Elmish repo too.

ghost avatar Jan 31 '18 19:01 ghost

All Elmish components are reusable by default. So I am not sure to understand.

Program, is not Elmish component but what we use to register an Elmish application which use Elmish component if we can say.

MangelMaxime avatar Jan 31 '18 19:01 MangelMaxime

Here I found a great comparision of those different UI concepts, including Elm Architecture. It is not, that they are not reusable, it is just the way that reuse can become tedious in practice though the repeated nesting. I don't know how to express that otherwise, I'm not a native English speaker after all :). I will try to code something that demonstrates the problem I mean.

I'm just asking those questions to support you to find the best way for building up a set of great Fulma.Elmish components that are of true reusability and can provide value over other existing approaches :).

ghost avatar Jan 31 '18 21:01 ghost

Hello @alfonsogarciacaro,

I am trying to convert an elmish component I built (sortable table) to the Fable.Helpers.React.reactiveCom. I followed this path because I had a fully working set of files with the Elmish architecture in place and the gap to convert it seemed smaller.

However I am facing one issue : I don't have Commands. The update function in the reactiveCom does not return any Command but an updated state.

I am currently trying to stick with the component functions signature and thus I removed the emitted command from the update function to put them somewhere in the view function but I get many React warnings and null errors. I assume then that the view function is not the right place.

Do you have any recommandation on how to transition from Fable.Elmish to reactiveCom without Commands?

Do you have any example of the reactiveCom used in an application ?

Kind regards, Edouard

EdouardM avatar Feb 19 '18 08:02 EdouardM

Hi @EdouardM! I haven't actually used reactiveCom in an application yet, we designed it together with @zaack mainly to isolate some state from the global state. But it's true it's very convenient to build stand-alone Elmish-ish components too. It shouldn't be difficult to add commands, as it's just a callback that receives a dispatch function, which only has to run update and then call .setState.

Do you want to give it a try and send a PR to fable-react? I can also have a look when I have a moment.

alfonsogarciacaro avatar Feb 19 '18 09:02 alfonsogarciacaro

Ok @alfonsogarciacaro I am going to give it a try and let you know.

EdouardM avatar Feb 19 '18 10:02 EdouardM

Hi! I've started using this date picker today and thought about changing it to issue two messages (value change and ui change) and exposing a few smaller view function (like for the input). But seeing this issue I can also go this way if that's still wanted as it would get rid of the second message already.

So stateful components, tiny Elmish components or the classic way?

stroborobo avatar Apr 29 '19 16:04 stroborobo

What about the new hook feature? Can it be a better fit here?

Nhowka avatar Apr 29 '19 16:04 Nhowka

TBH I didn't give too much thought to this issue in a while 😅.

If you want to stay in a functional approach hooks are indeed a way to make a function stateful.

MangelMaxime avatar Apr 29 '19 16:04 MangelMaxime

I'll have a look at those :)

stroborobo avatar Apr 30 '19 09:04 stroborobo

Hey guys, I'm having a little trouble using function components. Maybe I haven't understood what they are from a Fable point of view. Since most view functions are something like 'foo -> 'bar -> ('msg -> unit) -> ReactElement and a function components appears to be something like 'props -> ReactElement, can we actually use them inside of what I thought of as a typical view function "tree"?

I tried building a function 'props -> ReactElement (props as in an anonymous record that contains all the parameters) and calling Hooks.useState in there, but only got errors that I should call it inside the body of a function component.

This is where I am right now: https://github.com/stroborobo/Fulma/tree/datepicker-react-hook

stroborobo avatar Apr 30 '19 13:04 stroborobo

got errors that I should call it inside the body of a function component.

This is where I am right now: https://github.com/stroborobo/Fulma/tree/datepicker-react-hook

Probably that can be fixed using FunctionComponent.Of to let react know that the function is now a function component. Are you using the example?

Nhowka avatar Apr 30 '19 13:04 Nhowka

Very good tip, thank you, I missed that. 👍

stroborobo avatar Apr 30 '19 13:04 stroborobo

I just removed the renderer from the PR, so it's just the hook now, please have a look: #211

stroborobo avatar May 07 '19 09:05 stroborobo