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

Add Components*ReactHooks recipes #249

Conversation

pete-murphy
Copy link
Collaborator

Addresses #245.

I mostly translated the existing Components*HalogenHooks recipes. I think there's generally a benefit to being able to compare what amounts to the same UI in Halogen hooks and React hooks, but in this case it seems like the Halogen examples are meant to showcase how to communicate state from child to parent component. In React, that's not really possible, and in my implementation, all state is held in the parent and setter/updater functions are passed down to the children along with the state value. So, although I think this is how the examples would translate to idiomatic React, the motivation for implementing these particular UIs might not be as clear as it is with Halogen.

pure
$ R.div_
[ R.div
{ className: "box"
Copy link
Collaborator Author

@pete-murphy pete-murphy Dec 6, 2020

Choose a reason for hiding this comment

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

I used this "box" class name because the Halogen version uses it. There's no stylesheet for either of them when I run the make command, so maybe the style is applied in some other setting? Or was it left in the Halogen example by mistake?

Copy link
Owner

Choose a reason for hiding this comment

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

Possibly by mistake?

@pete-murphy pete-murphy force-pushed the @ptrfrncsmrph/add-react-component-recipes branch from 9555246 to 756a44e Compare December 6, 2020 03:50
@pete-murphy pete-murphy force-pushed the @ptrfrncsmrph/add-react-component-recipes branch 2 times, most recently from 16de957 to 0767705 Compare December 6, 2020 05:27
@pete-murphy pete-murphy force-pushed the @ptrfrncsmrph/add-react-component-recipes branch from 0767705 to 7cb13d4 Compare December 6, 2020 16:06
@milesfrain
Copy link
Collaborator

If we started with ComponentsReactHooks and the task was to make a HalogenHooks equivalent, then I think we'd just use a simple rendering function and bypass all the child component complexity of our existing ComponentsHalogenHooks.

So it would probably be better to come up with a slightly different use case for this example where there's clearer motivation for why the child component should track its own state that's independent from the parent. I'll think about this some more and report back if anything comes to mind.

@JordanMartinez
Copy link
Owner

@milesfrain Do you think this at least shows one clear difference between Halogen and React? Those are hard to come by.

@milesfrain
Copy link
Collaborator

Do you think this at least shows one clear difference between Halogen and React?

I think the fair difference to show is that Halogen can do some more complicated stuff (child-parent communication) at the expense of more complicated code.

But because this example is so basic, it just makes Halogen seem overly complex and difficult to work with. If we weren't trying to demonstrate these advanced inter-component communication techniques, we could simply mimic the React example (demo code in #253).

So maybe it's not the most appropriate to clone simplified uses-cases of Halogen-only features. I didn't foresee this complication when opening #245.

Ideally we'd be able to accomplish the following:

  • Demonstrate how to use components in React (Tic-Tac-Toe #251 could be really great for this).
  • Highlight some tradeoffs between frameworks.
    • Do this in a way that's not unfairly unflattering to any particular framework.

@pete-murphy
Copy link
Collaborator Author

pete-murphy commented Dec 8, 2020

Hm, if we track the render count of the parent component, the advantage of the HalogenHooks implementation becomes clear:

(I wonder, with both examples, if there's a better way to track renders, but this seems to work.)

So, they're not really equivalent implementations. If I were to try to get the same performance (measured by how often the parent re-renders) in React, it would be a lot trickier.

@milesfrain
Copy link
Collaborator

I like the render count tracking. Maybe change the text to "Parent Renders" for clarity and add a note about that in the readme. I guess this means the Halogen recipes should also be updated in this PR too.

The same "Parent Renders" indicator can also be applied to ComponentsInput. I'd actually like to split that into two recipes for clarity (proposed in #263), and so the parent renders distinction would only apply to the parent-querying-child case. Maybe displaying render count should be a separate third recipe to avoid cluttering-up the core lesson of the original recipe.

Sorry for stalling this review. I was hoping to have a moment of inspiration where a perfect example would come to mind, but that hasn't happened yet.

@pete-murphy
Copy link
Collaborator Author

No problem 🙂. I wonder if I should just trim this down to the one ComponentsReactHooks recipe (and add the "Parent Renders" count to it and its counterpart ComponentsHalogenHooks). I think that might be sufficient to demonstrate the difference between React and Halogen, if that's the value in this PR. Another variation (either in addition or in place of the current ComponentsReactHooks implementation) could show how messy things get in React when trying to replicate the rendering performance of the Halogen example, further demonstrating the tradeoffs.

Let me know what you think. I'm also happy to just add "Parent Render" counts to the three existing Components*HalogenHooks and these three Components*ReactHooks recipes for now.

@milesfrain
Copy link
Collaborator

milesfrain commented Jan 6, 2021

I'm also happy to just add "Parent Render" counts to the three existing Components*HalogenHooks and these three Components*ReactHooks recipes for now.

I think that's the best next step.

I made a typo in suggesting adding a parent render count to ComponentsInput, since that won't show show any contrast with React (although maybe that lack of contrast would also be illuminating). I meant to suggest the Components recipe.

Given how easy it is to mix these up, I wonder if it would be worthwhile to convert to more descriptive names. That could be a separate PR, but brainstorming some ideas here for now. Feel free to suggest alternatives.

  • Split Components into two recipes (proposed in Revisit Halogen and React Components* recipes #263):
    • ChildOutputToParent or ParentFromChild
    • ParentAskChild or ParentQueryChild
  • Change ComponentsInput to:
    • ParentToChilden
  • Change ComponentsMultiType to:
    • ParentQueryUniqueChildren

I don't know whether it would be better for the terminology to be Halogen-specific or more general. For example query versus ask or request.

I wonder if I should just trim this down to the one ComponentsReactHooks recipe

I think it's still nice to have full parity between the react and halogen recipes, so would be in favor of keeping all three.

@JordanMartinez
Copy link
Owner

Could we keep this as one recipe, but split each component into its own part and run all three of them in the same main?

main :: Effect Unit
main = do
  runhalogen1
  runReact1
  
  runHalogen2
  runReact2

?

@milesfrain
Copy link
Collaborator

There will likely need to be some DOM finagling to create the necessary nodes to launch each application (rather than just attaching directly to body). But assuming we can do that in a nice way, here are some other pros and cons:

Pro:

  • Fewer recipes.
  • Faster CI.
  • Less bloated recipe list.

Con:

  • Larger recipe.
  • Slightly more work to identify which output corresponds to which code.
  • Interspersed imports. Possibly a non-issue, but could be annoying for folks who copy-paste.

Unknown:

  • Comparability
    • I personally think it's easier to compare the recipes when they're standalone.

@afcondon
Copy link
Contributor

afcondon commented Jan 8, 2021

Specifically to the point about bloated recipe list - that's been on my mind a bit recently as i've been making extensive use of the recipe list to help me write Halogen Hooks things for the first time - i think that the solution to too many recipes would be better done by enabling filtering of a long list of small recipes rather than bundling recipes together.

i say this because the big win with recipe list (and, as i say, i've personally been benefitting from it recently) is enabling you to isolate the core code that tackles some facet of a larger problem.

Note that this doesn't have to be done on the README itself - we could make a nice little app that uses the same readme but offers some affordances (ie tags, checkboxes, ordering etc) to enable a person to quickly zero in on a recipe that helps them. That recipe app could itself be a recipe!

@milesfrain
Copy link
Collaborator

we could make a nice little app that uses the same readme but offers some affordances (ie tags, checkboxes, ordering etc)

This would be great. Could share some code between this and the interactive table of container APIs that's also on my wishlist.

@JordanMartinez
Copy link
Owner

@afcondon Thanks for the comment about the bloated recipe list. I agree with you that the bloat problem is better solved by presenting the list in a different manner rather than merging recipes together.

So, let's not merge these recipes into one, but keep them separate.

@pete-murphy
Copy link
Collaborator Author

pete-murphy commented Jan 17, 2021

I'm also happy to just add "Parent Render" counts to the three existing Components*HalogenHooks and these three Components*ReactHooks recipes for now.

I think that's the best next step.

I've added a parent render count to each of those six components. I hadn't realized until I started work on it that the only difference in behavior between the React and Halogen implementations is with the ComponentsMultiType* variations 😅, the others have the same rendering behavior, at least as they're currently implemented.

ComponentsHalogenHooks

ComponentsHalogenHooks

ComponentsReactHooks

ComponentsReactHooks

ComponentsInputHalogenHooks

ComponentsInputHalogenHooks

ComponentsInputReactHooks

ComponentsInputReactHooks

ComponentsMultiTypeHalogenHooks

ComponentsMultiTypeHalogenHooks

ComponentsMultiTypeReactHooks

ComponentsMultiTypeReactHooks

There also might be a concern that adding the render counter adds a MonadEffect constraint to the anyMonad in the Halogen examples.

@JordanMartinez
Copy link
Owner

Thanks for your work on this @ptrfrncsmrph!

Copy link
Owner

@JordanMartinez JordanMartinez left a comment

Choose a reason for hiding this comment

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

LGTM

pure
$ R.div_
[ R.div
{ className: "box"
Copy link
Owner

Choose a reason for hiding this comment

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

Possibly by mistake?

@JordanMartinez JordanMartinez merged commit c1b7bfb into JordanMartinez:master Jan 18, 2021
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.

4 participants