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

How to use "v-once" directive in JSX? #535

Closed
funny-family opened this issue Dec 28, 2021 · 10 comments
Closed

How to use "v-once" directive in JSX? #535

funny-family opened this issue Dec 28, 2021 · 10 comments
Labels
question Further information is requested

Comments

@funny-family
Copy link

funny-family commented Dec 28, 2021

🧐 Problem Description

Do not understand how to use "v-once" directive with jsx?

💻 Sample code

...
<div v-once>render once or not....</div>
...

🚑 Other information

When I try apply this directive I get error:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'deep')
    at withDirectives (runtime-core.esm-bundler.js?5c40:3019)
@funny-family funny-family added the question Further information is requested label Dec 28, 2021
@funny-family funny-family changed the title How to use "v-once" directive? How to use "v-once" directive in JSX? Dec 28, 2021
@CrownHanhard
Copy link

CrownHanhard commented Jan 27, 2022

If you want to execute an event . You can try this

<div onClickOnce = { your event }> content </div>

@funny-family
Copy link
Author

funny-family commented Jan 27, 2022

@CrownHanhard onClickOnce allows me to click on div once, but not render render it only once and no more. Still thanks!

@CrownHanhard
Copy link

Maybe like v-if, you can only do it in other ways For example, set a Watcheror initialize deep copy data

@funny-family
Copy link
Author

funny-family commented Jan 27, 2022

@CrownHanhard, I don't think it works this way because:

this

<div v-once>
  addadada
</div>

compiles into this:

import { setBlockTracking as _setBlockTracking, createTextVNode as _createTextVNode, createElementVNode as _createElementVNode } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return _cache[0] || (
    _setBlockTracking(-1),
    _cache[0] = _createElementVNode("div", null, [
      _createTextVNode(" addadada ")
    ]),
    _setBlockTracking(1),
    _cache[0]
  )
}

See here.

@CrownHanhard
Copy link

Yes, you are right! I found instructions such as: v-show, v-slots,html , text, model , models, etc. in the code, but I didn't find the instruction v-once. Look at this and this .It's all on line 142

@funny-family
Copy link
Author

🤔

@funny-family
Copy link
Author

Solution was right above me. Big bruh xD

import { setBlockTracking as _setBlockTracking, createTextVNode as _createTextVNode, createElementVNode as _createElementVNode } from "vue"

export function render(_ctx, _cache, $props, $setup, $data, $options) {
  return _cache[0] || (
    _setBlockTracking(-1),
    _cache[0] = _createElementVNode("div", null, [
      _createTextVNode(" addadada ")
    ]),
    _setBlockTracking(1),
    _cache[0]
  )
}

@tcastelly
Copy link

tcastelly commented Aug 3, 2022

Maybe it can help someone :)

The first parameter of the withMemo is the trigger. Here because the array is empty it's like a v-once.

import { defineComponent, ExtractPropTypes, withMemo } from 'vue';

const props = {
  msg: String,
} as const;

export default defineComponent({
  name: 'DisplayMsg',
  props,
  render(ctx: ExtractPropTypes<typeof props>, cache: unknown[]) {
    return withMemo([/* ctx.msg */], () => <h1>{ctx.msg}</h1>, cache, 0);
  },
});

I simplified to be able to call like this:
https://github.com/shenron/vite-demo/blob/master/src/components/DisplayMsgOnce.tsx

const setup = (p: Props) => {
  const memo = useMemo();

  const msgMemo = memo(() => [p.msg]);

  const msgOnceMemo = memo();

  return {
    msgMemo,
    msgOnceMemo,
  };
};

export default defineComponent({
  name: 'DisplayMsgOnce',
  props,
  setup,
  render(c: DisplayMsgOnce) {
    const { msgMemo, msgOnceMemo } = c;

    return (
      <ul>
        <li><small>v-once:</small> {msgOnceMemo(<span>{c.msg}</span>)}</li>
        <li><small>v-memo:</small> {msgMemo(<span>{c.msg}</span>)}</li>
      </ul>
    );
  },
});

@funny-family
Copy link
Author

Maybe it can help someone :)

The first parameter of the withMemo is the trigger. Here because the array is empty it's like a v-once.

import { defineComponent, ExtractPropTypes, withMemo } from 'vue';

const props = {
  msg: String,
} as const;

export default defineComponent({
  name: 'DisplayMsg',
  props,
  render(ctx: ExtractPropTypes<typeof props>, cache: unknown[]) {
    return withMemo([/* ctx.msg */], () => <h1>{ctx.msg}</h1>, cache, 0);
  },
});

I simplified to be able to call like this: https://github.com/shenron/vite-demo/blob/master/src/components/DisplayMsgOnce.tsx

const setup = (p: Props) => {
  const memo = useMemo();

  const msgMemo = memo(() => [p.msg]);

  const msgOnceMemo = memo();

  return {
    msgMemo,
    msgOnceMemo,
  };
};

export default defineComponent({
  name: 'DisplayMsgOnce',
  props,
  setup,
  render(c: DisplayMsgOnce) {
    const { msgMemo, msgOnceMemo } = c;

    return (
      <ul>
        <li><small>v-once:</small> {msgOnceMemo(<span>{c.msg}</span>)}</li>
        <li><small>v-memo:</small> {msgMemo(<span>{c.msg}</span>)}</li>
      </ul>
    );
  },
});

v-once dose not use withMemo under the hood

@zhiyuanzmj
Copy link
Contributor

Now, @vue-macros/jsx-directive@0.4.0 support v-memo & v-once directive.

// v-memo
<div
  v-for={i in list}
  v-memo={[selected === i]}
  key={i}
  onClick={() => (selected = i)}
>
  {i}: {selected}
</div>

// v-once
<div v-once>{selected}</div>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

No branches or pull requests

4 participants