Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We鈥檒l occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: Feliz.ElmishComponents vs Feliz.UseElmish #263

Closed
Dzoukr opened this issue Oct 8, 2020 · 9 comments
Closed

Question: Feliz.ElmishComponents vs Feliz.UseElmish #263

Dzoukr opened this issue Oct 8, 2020 · 9 comments

Comments

@Dzoukr
Copy link
Contributor

Dzoukr commented Oct 8, 2020

Hello friend, it's been a while I bothered you with some retarded question, so it's time for another take. 馃槀

Can you please somehow describe what is the difference between Feliz.ElmishComponents and Feliz.UseElmish? I see them both are React component having Elmish MVU parts. Are there any typical scenarios where you would choose one instead of another? I love easy of use of Feliz.UseElmish and just fear I am maybe missing something even cooler here. 馃槃

@Shmew
Copy link
Collaborator

Shmew commented Oct 8, 2020

So Feliz.ElmishComponents isn't very useful anymore, and predates Feliz.UseElmish. The reason for this is that originally Feliz.ElmishComponents was a class based component, which I rewrote as a function component. A bit after that, we realized that if it's a function component it's trivial to just convert it into a hook. That is how Feliz.UseElmish came to be. So now Feliz.ElmishComponents is really just a function component that calls the hook. In fact, if you look at the project for Feliz.ElmishComponents you'll see it's tiny now.

@Dzoukr
Copy link
Contributor Author

Dzoukr commented Oct 8, 2020

Thanks a lot, Cody!!! So if I get i correctly, Feliz.UseElmish is the default one, right now.

@Shmew
Copy link
Collaborator

Shmew commented Oct 8, 2020

Yeah, we mostly still have Feliz.ElmishComponents around to not break people. You can consider it to be deprecated.

@Dzoukr
Copy link
Contributor Author

Dzoukr commented Oct 8, 2020

Perfect! Thanks again!

@Dzoukr Dzoukr closed this as completed Oct 8, 2020
@MangelMaxime
Copy link
Contributor

If it is "deprecated" it could be a good idea to mark it "Obselete" and redirect people to the recommended API.

What do you think?

@Dzoukr
Copy link
Contributor Author

Dzoukr commented Oct 8, 2020

Yes, we are just discussing with colleagues from F# team that we should do PR to documentation (maybe with link to this issue)

@Dzoukr
Copy link
Contributor Author

Dzoukr commented Oct 8, 2020

Ok, I did it here - #264

@Zaid-Ajaj
Copy link
Owner

Zaid-Ajaj commented Oct 8, 2020

Are there any typical scenarios where you would choose one instead of another? I love easy of use of Feliz.UseElmish and just fear I am maybe missing something even cooler here. 馃槃

Hi Roman, good question!

The difference like Cody mentioned is that Feliz.UseElmish is written with hooks as opposed to a full component implementation of Feliz.ElmishComponents.

However, that is not the entire story, because Feliz.UseElmish also follows hook semantics when it comes to component re-initialization by the use of the dependency array as the last argument which is a big difference from Feliz.ElmishComponents that doesn't do that where reinitialization was hacky: making up unique component keys from the input, yikes!

Feliz.UseElmish can also be combined with other hooks like subscriptions in the same component.

What do I mean by "re-initialization"? Well, imagine you are loading the user profile component based on URL changes as follows:

#/user=profile/{userId} -> UserProfile { UserId = userId }

Basically, we want to re-initialize the UserProfile component (calling init to reset the state) when the input UserId changes:

type UserProfileProps = { UserId : int }
 
let UserProfile = React.functionComponent("UserProfile", fun (props: UserProfileProps) -> 
  let state, dispatch = React.useElmish(init props.UserId, update, [| props.UserId |])
  Html.h1 (sprintf "UserProfile(UserId=%d)" props.UserId)
)

// later on application  entry: 

React.router [
  router.onUrlChange (parseUrl >> UrlChanged >> dispatch) 
  router.children [
     match state.CurrentUrl with
     | [ "user-profile"; Route.Int userId ] -> UserProfile { UserId = userId }
     | _ -> Html.h1 "Not found" 
  ]
]

Because we providing the the dependency array [| props.UserId |] to the hook (third argument to the hook), the component will automatically refresh and call init again to reset the Elmish dispatch loop. This is what we want because init was a function of the input props.UserId so we want to call it again when the props of the components changes.

When neither the init nor the update function require additional input from the props of the component, you simply provide an empty dependency array:

let state, dispatch = React.useElmish(init, update, [| |])

This is typically used for components that don't need input from outside, like the entry component of the application.

It can be a bit tricky to get used to the dependency array but they make a lot of sense, read more about it in Conditionally firing an effect from the hook docs.

Final tip: Feliz.UseElmish is really powerful because it gives you a full-fledged Elmish dispatch loop the same way you are used to with traditional Elmish apps. However, setting up types for the state and messages can be a bit too much when your components are simple. Do you need a couple of state flags? Then a couple of state variables with React.useState might be enough. Do you need to fetch and render some data without further interaction? Then React.useDeferred might do the trick. I will go for Feliz.UseElmish for complicated pages which have many events and lots of use interaction.

@Dzoukr
Copy link
Contributor Author

Dzoukr commented Oct 8, 2020

Wow, typical Zaid's response. 馃槃 You should start teaching those things, man! I can finally understand. Thanks again! 鉂わ笍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants