Hacker News new | ask | show | jobs
by djrenren 932 days ago
I've found webcomponents to be really good at encapsulating anything that doesn't directly query application state.

Specifically there are two type of components that really thrive as web components (as opposed to react):

1. Highly interactive components - Components that implement complex interaction management (but sort of agnostic to application state) are ideal web components. You don't need to mess around with `useEffect` or `useMemo`. You get really tight control of rendering and state updates.

2. Highly internally stateful components - Components that track a lot of state that doesn't escape the component, work great as web component. You get strong encapsulation without a framework requirement.

React conflates two concepts that I think are better when separated: templates, and components. Templates provide a "re-render the world" approach, and components encapsulate state and interaction patterns. Conflating these two things causes the standard useEffect and useMemo headaches. It also means that any consumer of your component, must also use your templating system (react's render function).

The `lit` library does this separation extremely well, allowing you to implement components using templates if you want, or not. And consumers do not care how the internals are implemented.

5 comments

> React conflates two concepts that I think are better when separated: templates, and components.

Whether a React code base conflates them depends on the code base, but the more familiar terminology is container vs presentation. [1]

[1] https://www.patterns.dev/react/presentational-container-patt...

You can absolutely follow a discipline like this which recreates this separation in a framework that lacks it
I completely agree. Recently I listened to a podcast where Brad Frost talked about web components being useful for design systems, as you can make a button in a web component and have that defined no matter what JS framework the dev team (or teams) want to use company-wide.

One issue I see though and I almost feel dumb for saying it, I don't like how web component code looks. Using innerHTML feels really weird when your team is so used to using JSX for react components for example. I don't think this would stop me from researching web components more but does anyone feel similarly or have a solution or obvious answer for me in this area?

You don't have to use innerHtml. The ShadowRoot pretty much acts like a document. So you can also use appendChild. Combined with a template element you can completely avoid innheHtml. You could even use jsx to create the template element I suppose.

That said I think this is mostly a non-issue.

For me, it feels weird to have four file types I need to manage in order to define a UI, instead of just one.
lit [1] provides declarative templates for web components for example.

[1] https://lit.dev/

> You don't need to mess around with `useEffect` or `useMemo`. You get really tight control of rendering and state updates.

You don't need those in React either. Whatever you do in Web Components can probably (most likely) be done in React.

After all, Web Components are a solidified 2010-era design. The reason React has hooks now because people have moved on, and are exploring other ways of building stuff. The only mistake React did was to keep reactivity on component level (hence all the hooks and their weird rules) when most people moved on to more granular reactivity. Hell, even Angular did.

> You don't need those in React either.

I mean... sometimes you do, that's why they exist. But yeah, most of the time you don't.

> Whatever you do in Web Components can probably (most likely) be done in React.

Of course! React is a good and powerful framework. But everything you do in React can be done in Angular 1.0 or even backbone.js. As always with frameworks it's about the productivity / performance ratio for your team (or for libraries, the ratio for your consumers).

> After all, Web Components are a solidified 2010-era design.

A lot of the web components related APIs are being actively developed including constructable stylesheets, shadow DOM APIs and more. Regardless, the era of design is not a great point in either the "pro" or "con" column, and is usually an ambiguous shorthand for the actual quality being critiqued.

> I mean... sometimes you do, that's why they exist.

They exist because they're useful, but you can write traditional React components that look a lot closer to Web Components, if you think that's better.

Forgot to mention, the knock-on effect of this thought process is that if you want to adopt web components, you still need a templating approach. And you'll find that most of your code is templates, and only a few are really components.
I find that they can work very well with state but since state is typically passed via attributes (downstream), it means that components can only share state with each other via strings. I found this to be an advantage, not a drawback because simple interfaces are at the core of my coding philosophy and strings make it infeasible to pass complex instances or functions to other components.
Well, this is only sort of true. When you’re writing HTML you’re restricted to attributes but custom elements are JavaScript objects and are free to respond to property updates on the object. Relying solely on strings is a limitation of your templating engine.

For example lit-html templates support syntax like:

<my-element .someProp=${new Foo()}></my-element>

Interesting. I recognize that lit-html is much more lightweight than React and others but personally I really like to avoid any magic at all and I like being forced to pass strings between components. It reminds me of an Alan Kay quote about OOP "The big idea is messaging". You want your components to be passing around messages, not state. This seems to go against FP philosophy but I've found that it really works for OOP. After all, OOP is traditionally about state encapsulation and prioritizing concern boundaries over logic/state boundaries as in FP.

Note that it's still possible to pass complex objects to native we components but only imperatively via properties so it's a lot higher friction (as it should be).