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

Declaring JSX / TSX elements in setup, instead of render(), loses reactivity #172

Closed
davelsan opened this issue Oct 31, 2019 · 4 comments
Closed

Comments

@davelsan
Copy link

davelsan commented Oct 31, 2019

Using JSX or TSX we can modularize a component by declaring (somewhat) functional elements in variables. In Vue 2.x this is also possible, but every declared element has to go inside the render function and reactive variables are handled in data or computed, kind of breaking the flow of what I'm trying to accomplish.

Since with this API we kind of declare everything inside setup, I was wondering whether it'd be possible to also declare these modular elements there too, instead of in the returned render function.

I can do something like this and the component renders just fine, but count reactivity is lost:

export default createComponent({
  name: 'App',
  setup () {
    // Declaring <header> and <clicker> in setup kind of
    // helps to functionally group elements and logic
    const count = ref(0);
    const header = (
      <h1>
          Count has been updated { count.value } times
      </h1>
    );

    const clicker = (
      <button
        on-click={
          () => count.value++
        }
      >
        Clicker
      </button>
    );

    // But <header> and <clicker> have to be declared inside
    // the return render, else "count" loses its reactivity?
    return () => {
      // const header = ...
      // const clicker = ...
      return (
        <div id="app">
          { header  }
          { clicker }
        </div>
      );
    }
  },
});

Is there anything I can do here to accomplish this?

Don't know if what I'm asking horribly defiles any good practices standards out there, though...

Maybe somewhat related issues: #59, #64

UPDATE

I should have mentioned, just in case. I used @liximomo's vue-composition-api-tsx-example as the sandbox to run the code I've written above.

That repo installs babel-preset-vca-jsx, which automatically imports createElement as h and compiles the return of setup from JSX to a valid createElement object.

@dvic
Copy link

dvic commented Oct 31, 2019

I believe the setup function is run only once? (AFIK it replaces beforeCreate and created)

@davelsan
Copy link
Author

davelsan commented Oct 31, 2019

Would that mean I'm just returning those elements as static templates?

EDIT

Well, that might explain why if I declare them as arrow functions, then call them inside the return, reactivity works.

export default createComponent({
  name: 'App',
  setup () {
    // declare <header> and <clicker> elements as
    // arrow functions, execute them in the return
    const count = ref(0);
    const header = () => (
      <h1>
          Count has been updated { count.value } times
      </h1>
    );

    const clicker = () => (
      <button
        on-click={
          () => count.value++
        }
      >
        Clicker
      </button>
    );

    return () => {
      // execute header() and clicker() here to
      // retain reactivity
      return (
        <div id="app">
          { header()  }
          { clicker() }
        </div>
      );
    }
  },
});

@dvic
Copy link

dvic commented Oct 31, 2019

Yes, that's exactly the reason, I think this is expected behavior.

@davelsan
Copy link
Author

Alright. I'm going to leave this open for a day in case someone wants to add to the discussion. Thanks for the help @dvic, at least now I know why it happens and can work around it.

@davelsan davelsan closed this as completed Nov 1, 2019
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

No branches or pull requests

2 participants