33

I use Vue 3.1.1

I am using script setup in the experimental stage with single file components. Using the script setup, I understand defineProps, defineEmit, and useContext, but I don't understand how to use the render function.

<script lang="ts" setup>
import { defineProps } from 'vue'

const props = defineProps<{
    text: string
}>()

const handleClick = () => {
    console.log('click!!')
}

// Render function...

/* The template I want to create.
    <button
        class="btn btn-primary"
        type="button"
        @click="handleClick"
    >
        {{ props.text }}
    </button>
*/
</script>

4 Answers 4

31

try it.

<script lang="tsx" setup>
  import { h } from 'vue';

  const render = () => {
    return h('div', []);
  };

  const jsxNode = () => {
    return <div> text </div>;
  };
</script>
<template>
  <render />
  <jsxNode />
</template>

Sign up to request clarification or add additional context in comments.

2 Comments

HMR doesn't work in this form when you change code inside render or jsxNode
This answer is only a special implementation, and does not involve what effect HMR will show. But whether or not HMR is effective, this method should not be used in preference, because it will make the code less readable. Moreover, the appearance of setup script is to solve the troublesomeness that setup() needs to be exported. If your component doesn't need <template>, you don't need setup script at all, you should use jsx/tsx file
11

You can assign the render function directly to your component instance via getCurrentInstance

Custom hook

// useRender.ts

import type { VNode } from 'vue';
import { getCurrentInstance } from 'vue';

export function useRender(render: () => Arrayable<VNode | null>): void {
    const vm = getCurrentInstance();

    if (!vm) {
        throw new Error('[useRender] must be called from inside a setup function');
    }

    /**
     * In development mode, assignment render property works fine
     * but in production SFC overwrites it with an empty function
     * because no <template> section defined.
     *
     * Filthy hack to avoid this in production.
     * https://github.com/vuejs/core/issues/4980
     */
    if (import.meta.env.DEV) {
        (vm as any).render = render;
    } else {
        Object.defineProperty(vm, 'render', {
            get: () => render,
            set: () => {},
        });
    }
}

Usage

<script setup>
import { h } from 'vue';

import { useRender } from './useRender';

useRender(() => h('span', 'Hello from script setup'));
</script>

Comments

10

Try to use the h function to create your element then render it inside the template section as follows :

<script setup lang="ts">
import { ref,h } from 'vue'

const props = defineProps<{
    text: string
}>()

const handleClick = () => {
    console.log('click!!')
}

const root=h('button',
             {type:'button',onClick:handleClick,class:'btn btn-primary'},props.text)

</script>

<template>
  <root/>             
</template>

DEMO

6 Comments

This does not work.
@RafA. can you show how have you tried it?
Exactly like the that, except it was JS and not TS. Well I should probably state that this "kind of" works, but it does not convert dynamic components. So if you write in that h() innerHTML: "<router-link>...." - it will not work.
Do you mean that you wrote h('router-link',...)?
For component try to import it then use it as first parameter, import {RouterLink} from 'vue-router'; and h(RouterLink,...)
|
-4

You may try an extra normal script.

<script lang="tsx" setup>
import { defineProps, defineExpose } from 'vue'

const props = defineProps<{
    text: string
}>()

const handleClick = () => {
    console.log('click!!')
}
defineExpose({
  handleClick,
  // other data,method
})
</script>

<script lang="tsx">
import { defineComponent } from 'vue'

export default defineComponent({
  render() {
    return (
      <button
        class="btn btn-primary"
        type="button"
        onClick={this.handleClick}
      >
        {{ this.text }}
      </button>
    )
  }
})
</script>

Any data, methods except the props should be exposed using defineExpose.

BTW, setup script and normal script should have the same lang attribute.

1 Comment

this doesn't work in production mode.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.