Lit-element: Please put render property params back

Created on 15 Sep 2018  路  11Comments  路  Source: Polymer/lit-element


Description

In previous versions of LitElement, _render was a unary method which took an object map of props:

_render({active, disabled}) {
  return html`<button disabled?="${disabled}"></button>`
}

Since 0.6 this parameter has been removed

render() {
  const { active, disabled } = this
  return html`<button ?disabled="${disabled}"></button>`
}

While there were cases (for example, complex nested data) in which parameter destructuring was harmful, in general, passing the parameters made the render method purer and more understandable. Since the purpose of lit-html and LitElement is to enable authors to factor web-component-based UIs as a pure function of state, magical references to this should be avoided whenever possible.

To be clear: if this suggestions is taken, there may still be times when referencing this in the body of render is desired, however, we should enable the simple case to be as pure as possible.

Versions

  • lit-element: ^0.6

Most helpful comment

I believe the main disadvantage of the previous system when render accepts all properties as params was that you can do rendering using two different approaches.

The first one is absolutely functional, it allowes to avoid using this inside render at all. Why should you do that if everything you need is accessible by function params?

render({active, disabled}) {
  return html`<button disabled?="${disabled}"></button>`
}

The second one is purely OOP. You have a this context, you can use it anywhere inside render and you can use everything class could provide.

render() {
  return html`<button ?disabled="${this.disabled}"></button>`
}

Having two different system is confising. I never understood why the first one even exist. If you want functional approach, why don't you make the render static? It sounds way more convenient than having a half-baked class member that can use OOP features and can avoid doing that.

But it isn't convenient, right? Because if we do so we will loose many comfortable things like splitting template to parts and putting them to separate class methods. Or all our functions should be bound. Or we should think about another approach to do things that are already solved by OOP functionality here.

Thus, if we already have excellent approach that allows us to do whatever we want, why should we have the another one? To create a situation when you think: "Should I get this function from params? Oh no, it's just an unbound method, I need to use this here"? I would say it again: it's confusing. It adds complexity in the place it shouldn't actually exist. That's why I think that removing the confusing part of functionality is a good thing.

All 11 comments

I respectively disagree that this should've remained a feature in LitElement 馃檪. Lit Element is a class that ultimately is the caller of the render() and it seems weird to ever call the render method with a different context other than the instance of itself (this). It seems that is the only case where anyone would want the params back, because passing them to the render() method would be necessary and not optional.

If the goal for you is to use a pure rendering mechanism, lit-html may be the best solution, which will allow you to create your own custom render() function to pass what you want to it.

We've obviously gone back and forth on this. The current notion is that render should be a pure function of the state of the element which is best described by the properties of this.

If render depends on this, then by definition it's not a pure function anymore. The readme states that it should be a pure function. So if render params won't be passed to render anymore, would it be appropriate to change the readme to not call render a pure function?

https://medium.com/javascript-scene/master-the-javascript-interview-what-is-a-pure-function-d1c076bec976

https://en.wikipedia.org/wiki/Pure_function

Although I prefer a functional style wherever possible, I prefer the new style because of https://github.com/Polymer/lit-element/pull/112 (look at the closing comment)

@merlinnot not every LitElement user is a typescript user. Why should the limits of TS's typing system negatively affect the LitElement API?

I for one will not be using TypeScript. :)

I believe the main disadvantage of the previous system when render accepts all properties as params was that you can do rendering using two different approaches.

The first one is absolutely functional, it allowes to avoid using this inside render at all. Why should you do that if everything you need is accessible by function params?

render({active, disabled}) {
  return html`<button disabled?="${disabled}"></button>`
}

The second one is purely OOP. You have a this context, you can use it anywhere inside render and you can use everything class could provide.

render() {
  return html`<button ?disabled="${this.disabled}"></button>`
}

Having two different system is confising. I never understood why the first one even exist. If you want functional approach, why don't you make the render static? It sounds way more convenient than having a half-baked class member that can use OOP features and can avoid doing that.

But it isn't convenient, right? Because if we do so we will loose many comfortable things like splitting template to parts and putting them to separate class methods. Or all our functions should be bound. Or we should think about another approach to do things that are already solved by OOP functionality here.

Thus, if we already have excellent approach that allows us to do whatever we want, why should we have the another one? To create a situation when you think: "Should I get this function from params? Oh no, it's just an unbound method, I need to use this here"? I would say it again: it's confusing. It adds complexity in the place it shouldn't actually exist. That's why I think that removing the confusing part of functionality is a good thing.

@Lodin since lit-html is in essence a functional library, in this case, I think it makes sense to keep render pure. it's even in the docs:

Thinking Functionally
lit-html is ideal for use in a functional approach to describing UIs. If you think of UI as a function of data, commonly expressed as UI = f(data), you can write lit-html templates that mirror this exactly:

let ui = (data) => html`...${data}...`;

- lit-html docs

Since most users will be using lit-html via it's element base class, render should remain functional in nature. This would reflect the larger sea-change in the JS world towards functional patterns.

This _isn't_ lit-html though, this is lit-element which is all based around classes and instance properties.

@bennypowers Yes, as @CaptainCodeman said, we're talking about lit-element now. lit-html is completely separate library with completely different approach and it definitely has its pure render function. lit-html is about declarative rendering, and lit-element is about providing tools to create custom elements. Don't mix them up.

That's also correct for conceptions used by these projects. I believe that we shouldn't mix up them as well. There is a great example of completely functional approach - an amazing Switzerland project. It allows creating Custom Elements using only functions. No classes - well, they're hidden under the hood, but basically you use only functions. Unfortunately, it uses Virtual DOM, not lit-html as a rendering system because it appeared before lit-html was born.

However, lit-element is not Switzerland. It doesn't declare functional approach, futhermore, it provides classical OOP style to work with Custom Elements. And mixing things OOP is responsible for with functional approach looks confusing. Things should be consistent.

Was this page helpful?
0 / 5 - 0 ratings