【问题标题】:Vue 3 Typescript ComputedRef IssuesVue 3 Typescript ComputedRef 问题
【发布时间】:2022-01-09 00:08:42
【问题描述】:

我偶然发现了 Typescript 和 Vue3 的一些问题。我想我在这里用错了 Typescript。

我使用 Vue 的 Composition API 创建了自己的商店。

import {computed, reactive} from "vue";

const state = reactive({
    accessToken: undefined,
    user: {},
})

const isAuthenticated = computed(() => {
    return state.accessToken !== undefined
})

export default {
    state: readonly(state),
    isAuthenticated
}

为它写一个类型/接口:

import {ComputedRef} from "vue";

export interface UserStore{
    state: Readonly<any>;
    isAuthenticated: ComputedRef<boolean>;
}

但是当我现在想在我的 vue 组件中使用它时。

例如这样:

<h1 v-if="userStore.isAuthenticated">is true</h1>

即使明显为假,它也会返回真。

我通过 inject 注入 store:

setup(){
    return {
      userStore: inject('userStore') as UserStore
    }
  }

当我想返回一个 computed() 字符串时会出现类似的问题。当我在模板中使用它时,它被包含在引号中。

这里有什么问题?

#编辑 我在 main.ts 中提供 UserStore

/* Stores */
import UserStore from './store/user-store'

const app = createApp(App)
  .use(IonicVue, {
    mode: 'ios'
  })
  .use(router)
.provide('userStore',UserStore);

router.isReady().then(() => {
  app.mount('#app');
});

【问题讨论】:

  • 你在哪里provideuserStore?似乎是反应性问题,而不是打字稿问题。
  • 我在 main.ts 中将它提供给 vue 应用程序。上面编辑:)

标签: typescript vue.js


【解决方案1】:

如果你想在 typescript 中创建一个计算属性,你需要添加一个 get infront of 方法。

get isAuthenticated () {
    return state.accessToken !== undefined
)

制作类型接口

interface recordTypes {
    pDate: Date;
}

这是完整的例子

<template>
   
    <component
        v-if="componentName != ''"
        v-bind:is="componentName"
        v-on:updateConfirmationStatus="updateConfirmation"
    >
    </component>

   
</template>

<script lang="ts">
import { Vue, Options } from "vue-class-component";
import { useStore, ActionTypes } from "../store";
import Toaster from "../helpers/Toaster";
import { reactive } from "vue";
import PatientConsultationService from "../service/PatientConsultationService";
import Confirmation from "../components/Confirmation.vue";
import { required } from "@vuelidate/validators";
import useVuelidate from "@vuelidate/core";
import { camelCase } from "lodash";
import moment from "moment";

interface recordTypes {
    pDate: Date;
}

@Options({
    components: {
        Confirmation
    }
})
export default class Assessments extends Vue {
    private recordList: recordTypes[] = [];
    private recordID = 0;
    private pService;
    private isCollapsed = true;
    private submitted = false;
    private toast;
    private componentName = "";
    private vuexStore = useStore();

    private state = reactive({
        weight: 0,
        height: 0,
        o2: 0,
        respiration: 0,
        temperature: 0,
        pressure: 0,
        pulse: 0
    });

    private validationRules = {
        weight: {
            required
        },
        height: {
            required
        },
        o2: {
            required
        },
        respiration: {
            required
        },
        temperature: {
            required
        },
        pressure: {
            required
        },
        pulse: {
            required
        }
    };

    private v$ = useVuelidate(this.validationRules, this.state);

    created() {
        this.pService = new PatientConsultationService();
        this.toast = new Toaster();
    }

    mounted() {
        this.loadList();
    }

    get patientID() {
        return this.vuexStore.getters.getReceiptID;
    }

    saveItem(isFormValid) {
        this.submitted = true;
        if (isFormValid) {
            this.pService
                .saveAssessment(this.state, this.patientID)
                .then(res => {
                    this.clearItems();
                    this.toast.handleResponse(res);
                    this.loadList();
                });
        }
    }

    clearItems() {
        this.state.weight = 0;
        this.state.height = 0;
        this.state.o2 = 0;
        this.state.respiration = 0;
        this.state.temperature = 0;
        this.state.pressure = 0;
        this.state.pulse = 0;
    }

    loadList() {
        this.pService.getAssessment(this.patientID).then(data => {
            const res = this.camelizeKeys(data);
            this.recordList = res.records;
        });
    }

    camelizeKeys = obj => {
        if (Array.isArray(obj)) {
            return obj.map(v => this.camelizeKeys(v));
        } else if (obj !== null && obj.constructor === Object) {
            return Object.keys(obj).reduce(
                (result, key) => ({
                    ...result,
                    [camelCase(key)]: this.camelizeKeys(obj[key])
                }),
                {}
            );
        }
        return obj;
    };

    get sortedRecords() {
        let sortedList = {};

        this.recordList.forEach(e => {
            const date = String(e.pDate);
            if (sortedList[date]) {
                sortedList[date].push(e);
            } else {
                sortedList[date] = [e];
            }
        });

        return sortedList;
    }

    formatDate(d) {
        const t = moment().format("YYYY-MM-DD");
        let fd = "";

        if (d == t) {
            fd = "Today " + moment(new Date(d)).format("DD-MMM-YYYY");
            this.isCollapsed = false;
        } else {
            fd = moment(new Date(d)).format("DD-MMM-YYYY");
            this.isCollapsed = true;
        }

        return fd;
    }

    deleteItem(id) {
        this.vuexStore.dispatch(
            ActionTypes.GET_RECEIPT_TITLE,
            "Are you sure to delete this"
        );
        this.componentName = "Confirmation";
        this.recordID = id;
    }

    updateConfirmation(b) {
        this.componentName = "";
        if (b.result) {
            this.pService.deleteAssessment(this.recordID).then(res => {
                this.toast.handleResponse(res);
                this.loadList();
            });
        }
    }
}
</script>

【讨论】:

  • 应该在哪里添加? Vue类中使用了getter语法,这里没有用到
  • 添加了一个例子,请检查
  • 您的示例使用了 Vue 类。问题中未使用它们。
【解决方案2】:

ref 是一个对象,所以userStore.isAuthenticated 表达式总是真实的。

当从 setup 函数返回时,Refs(包括计算的)会自动在模板中展开。应该是:

const userStore = inject('userStore') as UserStore
const { isAuthenticated } = userStore;

return {
  isAuthenticated
}

否则需要手动解包 ref:

<h1 v-if="userStore.isAuthenticated.value">is true</h1>

【讨论】:

  • 你也可以使用toRef从reactive中提取一个引用,然后省略valuereturn {isAuthenticated: toRef(userStore, 'isAuthenticated') }
猜你喜欢
  • 1970-01-01
  • 2021-07-08
  • 2021-12-01
  • 2021-12-22
  • 2021-01-15
  • 2023-01-22
  • 2021-07-03
  • 2021-07-08
  • 2021-10-19
相关资源
最近更新 更多