This is the package to use PromiseComponent with Vue.
English | 简体中文
npm i @promise-components/vue
Let's implement a user list and include the ability to interactively add and edit user information using a dialog box.
You need to use the shared rendering slot of the Promise component in the root component, which will provide a default rendering location for the Promise components of the entire application and inheritance of the application context (such as: store, theme, i18n...).
<!-- App.vue -->
<script setup lang="ts">
import { SharedSlot } from '@promise-components/vue'
</script>
<template>
<div>
...
<SharedSlot/>
</div>
</template>
<!-- add-user.vue -->
<script setup lang="ts">
import { PromiseResolvers } from '@promise-components/vue'
import { reactive } from 'vue'
interface UserItem {
name: string
age: number
id: number
}
/**
* 🔴 The Props parameter must inherit from PromiseResolvers
*/
interface Props extends PromiseResolvers<UserItem> {
user?: UserItem
}
const props = defineProps<Props>()
const formData = reactive<UserItem>({
name: '',
age: 0,
id: Math.random(),
...props.user, // If editing, fill in the default value
})
function handleSubmit () {
if (!formData.name) return alert('Please enter `Name`')
if (!formData.age) return alert('Please enter `Age`')
// 🔴 Call resolve callback
props.resolve(formData)
}
function handleCancel () {
// 🔴 Call reject callback
props.reject()
}
</script>
<template>
<dialog open>
<form>
<p>
<span>Name: </span>
<input v-model="formData.name" type="text"/>
</p>
<p>
<span>Age: </span>
<input v-model="formData.age" type="number"/>
</p>
</form>
<p>
<button @click="handleCancel">Cancel</button>
<button @click="handleSubmit">Submit</button>
</p>
</dialog>
</template>
Since the Promise component instance cannot be exported directly in the .vue
file, an additional .ts
file is
required to create the instance.
// add-user.promise.ts
import { PromiseComponent } from '@promise-components/vue'
import Component from './add-user.vue'
export const AddUser = new PromiseComponent(Component)
File name suggestions:
- Main:
index.ts
- Named:
[name].promise.ts
<!-- user-list.vue -->
<script setup lang="ts">
import { ref } from 'vue'
import { AddUser } from './add-user.promise.ts'
interface UserItem {
name: string
age: number
id: number
}
const userList = ref<UserItem[]>([])
async function handleAdd () {
/**
* 🔴 Using component
*/
const newUser = await AddUser.render()
userList.value.push(newUser)
}
async function handleEdit (editIndex: number) {
const target = userList.value[editIndex]
/**
* 🔴 Using component and providing parameters (Edit mode)
*/
const modifiedUser = await AddUser.render({
user: target,
})
Object.assign(target, modifiedUser)
}
</script>
<template>
<div>
<ul>
<li v-for="(item, index) in userList" :key="item.id">
<span>Name: {{item.name}}, Age: {{item.age}}</span>
<button @click="handleEdit(index)">Edit</button>
</li>
</ul>
<button @click="handleAdd">Add</button>
</div>
</template>
Well, we have happily completed the development of the user list function based on the Promise component.
If you want to render a Promise component in a specific location, you can use the custom slot of the Promise component.
<!-- user-list.vue -->
<script setup lang="ts">
import { AddUser } from './add-user.promise.ts'
</script>
<template>
<div>
...
<AddUser.Slot/>
</div>
</template>
import { ComponentOptions, Component } from 'vue'
/**
* The basic props of the PromiseComponent
* @property resolve Promise Operation Success Callback (Resolved)
* @property reject Promise Operation Failure Callback (Rejected)
*/
interface PromiseResolvers<T> {
resolve: (value: T) => void;
reject: (reason?: any) => void;
}
/**
* Public slot of Promise components
*/
declare const SharedSlot: ComponentOptions
/**
* Promise component constructor
*/
declare class PromiseComponent<T extends PromiseResolvers<any>, P = Omit<T, keyof PromiseResolvers<any>>, R = Parameters<T['resolve']>[0]> {
constructor (public Component: Component<T>);
/**
* promise rendering
* @param props component props
*/
render (props?: P): Promise<R>;
/**
* Custom slot for Promise component
*/
Slot: ComponentOptions
}
export {
PromiseComponent,
type PromiseResolvers,
SharedSlot,
}