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’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use Elmish.Program in useElmish #414

Merged
merged 4 commits into from
Nov 5, 2021

Conversation

alfonsogarciacaro
Copy link
Contributor

This fixes fable-compiler/fable-promise#24 following @MangelMaxime suggestion to use the Elmish.Program implementation instead of adding a custom one.

I've tested this in a project of mine and also in Fable.Lit and it seems to work. Feliz tests are also passing. The PR is still missing the dependencies, but if you're open to merge this @Zaid-Ajaj I can add them too.

let rec dispatch (msg: 'Msg) =
promise {
let mutable nextMsg = Some msg
static member useElmish(program: unit -> Program<unit, 'State, 'Msg, unit>) =
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we avoid forcing the 'arg type to unit?

Some program can use another parameter than unit for their initial arguments.

Elmish Program definition: type Program<'arg, 'model, 'msg, 'view>

For the view, I suppose you made it unit because we are inside of a hooks and so don't have a view to render in this context?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, yes. That makes sense, I was mainly thinking in the case when you pass the init and update function, but it should be no problem to accept other args than unit.

About it he view, yes. The view code comes after the hooks, so it doesn't make sense at this point and this is why it's set to unit. Incidentally, this should also make it easier to reuse Elmish programs with different renderers like React or Lit.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MangelMaxime I've made the changes to accept an arg other than unit. You're right this is probably useful to have an init function that depends on props passed to the component.

About view, it would be possible to have an overload useElmishthat accepts a Program with a view function (or alsouseElmish(init, update, view)) and returns directly a ReactElement. However when designing something similar for useLit` @Zaid-Ajaj commented that a helper returning ReactElement is not actually a hook, so not sure if it can create an issue with React tooling.

@Zaid-Ajaj
Copy link
Owner

Hi @alfonsogarciacaro,

I've been out of the loop on this one. Not I totally understand what the underlying issue was in fable-promise 😅

Regardless of that iusse, I think it is a good idea to use the existing implementation of Elmish inside of Feliz.UseElmish and remove the dependency of Fable.Promise from Feliz.UseElmish ✅

However, I am not sold on accepting a full Program<_> as input because I want to keep the API simple: accepting init, update and the dependencies array. I am afraid it might be confusing to users as to how the dependencies array play with the full program and also the fact that programs deal with the view whereas here we don't need to ⚠

The PR is still missing the dependencies, but if you're open to merge this @Zaid-Ajaj I can add them too.

That would be great!

@MangelMaxime
Copy link
Contributor

However, I am not sold on accepting a full Program<_> as input because I want to keep the API simple: accepting init, update and the dependencies array. I am afraid it might be confusing to users as to how the dependencies array play with the full program and also the fact that programs deal with the view whereas here we don't need to warning

The view inside of Elmish program is a slot reserved for program that need to have Elmish handle the view. You can use Elmish without any view this is for example what I do in a CLI application where I use Elmish only for the state management.

Allowing the hook to accept a program as an entry is important to allow people to augment their Elmish program like it is done for HMR, Navigation, debugger, etc.

Because we are using methods, to define the UseElmish hooks we can always declare a method accepting the program as an arguments and another one asking for init, update, deps as it is done right now.

The second version would just call the first overload to make it transparent to the user.

@Zaid-Ajaj
Copy link
Owner

Allowing the hook to accept a program as an entry is important to allow people to augment their Elmish program like it is done for HMR, Navigation, debugger, etc.

In practice I am a bit concerned about their use cases. Usually users augment their top-level program with things that are application-wide such as Navigation and HMR but when using Feliz.UseElmish, the idea is to make the program local to a single component.

What happens when multiple React components with useElmish register the HMR extension? This were built with the idea that there will only be one entry point to the Elmish app.

The second version would just call the first overload to make it transparent to the user.

Yeah an overload would make sense

@MangelMaxime
Copy link
Contributor

What happens when multiple React components with useElmish register the HMR extension? This were built with the idea that there will only be one entry point to the Elmish app.

For HMR, it would not work indeed because I am using a fixed name global variable. But this should be fixable.

But in their case, it was more to attach the Redux debugger for example.

I just gave a list of publicly existing program augmentation as an example.

I think offering it as an overload for expert user makes sense as right now if they need to access it they can't and have to copy/paste and adapt the source from Feliz repository.

@Zaid-Ajaj
Copy link
Owner

I think offering it as an overload for expert user makes sense as right now if they need to access it they can't and have to copy/paste and adapt the source from Feliz repository.

Sounds like a good idea then. Let's get this in ✅

@alfonsogarciacaro
Copy link
Contributor Author

I tried to add the "reset" when dependencies change but the test is failing. Not entirely sure why, I'll try to investigate.

BTW, it'd be nice to move already tests to Fable 3 and use some better tooling. Right now tests take a long time to run, there's no watch mode and I cannot see which assertion is failing, so it's difficult to spot the problem.

@alfonsogarciacaro alfonsogarciacaro changed the title [WIP] Use Elmish.Program in useElmish Use Elmish.Program in useElmish Oct 29, 2021
@alfonsogarciacaro
Copy link
Contributor Author

Ok, tests are passing now, I was using upper case for one the test ids 😅 But it took me a while to realize that, I had to create a different project for it. So it would still be nice to update the tests to Fable 3 and enable a test watcher. I can do that in a different PR if that's ok with you.

This PR is now ready to merge btw 👍

@alfonsogarciacaro
Copy link
Contributor Author

@Zaid-Ajaj Would it be possible to review the PR when you've a moment and merge if everything's ok? Thanks a lot!

Note: if for some reason you cannot maintain this package anymore, we could publish UseElmish hook as an independent package from Feliz (only with Fable.React dependency) but in that case it's probably better to deprecate the current package so users are not confused by two competing options.

@Zaid-Ajaj Zaid-Ajaj merged commit e1e575c into Zaid-Ajaj:master Nov 5, 2021
Zaid-Ajaj added a commit that referenced this pull request Nov 5, 2021
@Zaid-Ajaj
Copy link
Owner

Hi @alfonsogarciacaro, sorry for the delay 🙏 I have now merged and published this implementation as of Feliz.UseElmish v1.6 🚀

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

Successfully merging this pull request may close these issues.

Feliz.Router.BasePath stopped navigation
3 participants