ryansolid / dom-expressions

A Fine-Grained Runtime for Performant DOM Rendering
MIT License
874 stars 125 forks source link

`this` inside arrow function is incorrect after Solid transform #292

Closed trusktr closed 10 months ago

trusktr commented 10 months ago

Reproduction:

https://playground.solidjs.com/anonymous/ab9e79a2-8bb0-4e1d-96cd-f55b12d0242e

A workaround is to avoid arrow functions, here with a regular method:

https://playground.solidjs.com/anonymous/e80be486-0bc4-4512-b4d0-c1dad21ee863

The transform is replacing this with a variable that grabs this from somewhere unrelated to the code, f.e. like so:

const _self$ = this; // <--------- HERE
const ClickCounter = element(class ClickCounter extends Element {
  template = () => (() => {
    // ...
    _$insert(_el$, () => _self$.count, _el$4); // <---- HERE
    return _el$;
  })();
});

At the top level of a module, this is undefined.

lxsmnsyc commented 10 months ago

Yeah seems like this is pushed in the wrong scope.

edit: https://github.com/ryansolid/dom-expressions/blob/82c377d19c7e096fe92e04411e1d332536cddec5/packages/babel-plugin-jsx-dom-expressions/src/shared/transform.js#L50

This is the culprit. The workaround could be to find the nearest function or block parent, and then move the declaration there.

trusktr commented 10 months ago

Why do we need a declaration? Why not leave this as-is considering that the output's wrapper is also an arrow function?

lxsmnsyc commented 10 months ago

@trusktr It's to protect reactive properties from accessing the props object.

For example:

<Div title={this.title} />

// if preserved
createComponent(Div, {
  get title() {
    return this.title; // recursive
  },
});

Origin: https://github.com/ryansolid/mobx-jsx/issues/44