提供在上下文中定义的const

发布于 2025-02-03 17:01:44 字数 2959 浏览 3 评论 0原文

我面临着需要创建一个api通话的情况,但是在安装组件之前,不应触发它。

这就是我到目前为止得到的:

onMounted(async() => {
    const {
        data,
        refresh,
        pending,
        error
    } = await useApi(`/profile/${$auth.user.profile.sid}`, null, ['data']);

});

const computedWaiting = computed<boolean>(() => {
    return pending.value === true;
});

现在问题是,computedWaiting引发错误,因为未定义。因此,我需要破坏useapi -Response,这基本上是 https:> https: //github.com/unjs/ohmyfetch-result

这是USEAPI-Method(取自此github-issue: https://github.com/ NUXT/FRAFERWORK/JEARDIONS/4504 ):

import {FetchOptions} from "ohmyfetch";

const csrf_cookie: string = "XSRF-TOKEN";

/**
 * Return the cookies needed by "Sanctum", browser will handle them automatically.
 */
export const useFetchCookies = async () => {

    await $fetch.raw("/backend/sanctum/csrf-cookie", {
        credentials: "include" // Allow browser to handle cookies
    });
};

/**
 * Api call using nuxt `useFetch`
 *
 * @see {@link https://github.com/unjs/ohmyfetch#readme} ~ ohmyfetch Docs
 * @param url
 * @param options
 * @param pick
 */
export const useApi = async (url: string, options?: FetchOptions, pick?: any) => {

    // First we verify if the `xsrf-token` is present on the browser cookies
    let token = useCookie(csrf_cookie)?.value;

    if (!token) {
        // If not present we will re fetch all cookies, the browser will
        // handle them automatically so we don't need to do anything
        await useFetchCookies();

        // Load the new token value to use it in the `headers`
        token = useCookie(csrf_cookie).value;
    }

    // Here we will create a default set of headers for every request
    // if present we will also spread the `headers` set by the user
    // then we will delete them to avoid collision in next spread
    const headers: HeadersInit = {
        Accept: "application/json",
        "Cache-Control": "no-cache",
        "X-XSRF-TOKEN": token,
        ...options?.headers
    };

    // At this point all the `headers` passed by the user where correctly
    // set in the defaults, now we will spread `options` to remove the
    // `headers` attribute so we don't spread it again in `useFetch`
    const opts: FetchOptions = options ? (({headers, ...opts}) => opts)(options) : null;

    return useLazyFetch(`/backend/api${url}`, {
        server: false,
        credentials: "include", // Allow browser to handle cookies
        headers,
        ...opts,
        pick: pick
    });

};

知道usefetch来自

所以我如何将data> data REFRESH REFRESH REFRES> REFRESH >未决和错误在登上后最优雅?

I am facing a situation where I need to create an API-call, but it should not be fired until the component is mounted.

That's what I got so far:

onMounted(async() => {
    const {
        data,
        refresh,
        pending,
        error
    } = await useApi(`/profile/${$auth.user.profile.sid}`, null, ['data']);

});

const computedWaiting = computed<boolean>(() => {
    return pending.value === true;
});

Now the problem is, that the computedWaiting throws an error, as pending is not defined. So I would need to destruct the useApi-response, which is basically an https://github.com/unjs/ohmyfetch-result.

This is the useApi-method (taken from this GitHub-Issue: https://github.com/nuxt/framework/discussions/4504):

import {FetchOptions} from "ohmyfetch";

const csrf_cookie: string = "XSRF-TOKEN";

/**
 * Return the cookies needed by "Sanctum", browser will handle them automatically.
 */
export const useFetchCookies = async () => {

    await $fetch.raw("/backend/sanctum/csrf-cookie", {
        credentials: "include" // Allow browser to handle cookies
    });
};

/**
 * Api call using nuxt `useFetch`
 *
 * @see {@link https://github.com/unjs/ohmyfetch#readme} ~ ohmyfetch Docs
 * @param url
 * @param options
 * @param pick
 */
export const useApi = async (url: string, options?: FetchOptions, pick?: any) => {

    // First we verify if the `xsrf-token` is present on the browser cookies
    let token = useCookie(csrf_cookie)?.value;

    if (!token) {
        // If not present we will re fetch all cookies, the browser will
        // handle them automatically so we don't need to do anything
        await useFetchCookies();

        // Load the new token value to use it in the `headers`
        token = useCookie(csrf_cookie).value;
    }

    // Here we will create a default set of headers for every request
    // if present we will also spread the `headers` set by the user
    // then we will delete them to avoid collision in next spread
    const headers: HeadersInit = {
        Accept: "application/json",
        "Cache-Control": "no-cache",
        "X-XSRF-TOKEN": token,
        ...options?.headers
    };

    // At this point all the `headers` passed by the user where correctly
    // set in the defaults, now we will spread `options` to remove the
    // `headers` attribute so we don't spread it again in `useFetch`
    const opts: FetchOptions = options ? (({headers, ...opts}) => opts)(options) : null;

    return useLazyFetch(`/backend/api${url}`, {
        server: false,
        credentials: "include", // Allow browser to handle cookies
        headers,
        ...opts,
        pick: pick
    });

};

It could be helpful to know that useFetch comes from https://v3.nuxtjs.org/guide/features/data-fetching, which basically uses ohmyfetch as a composable itself: https://github.com/nuxt/framework/blob/46c656c4b85c3622b99a7c4f6a01f5b11c830be6/packages/nuxt/src/app/composables/fetch.ts#L18-L59

So how can I expose the data, refresh, pending and error most elegantly after onMounted?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

生活了然无味 2025-02-10 17:01:44

在没有特定目的的情况下,在on mounted中调用可复合的合并是不正确的。 VUE组合通常将直接用于设置功能,因此可以立即访问结果。是否可以在其他地方使用它们取决于它们的实现。

如果组合涉及异步副作用,它应该返回反应性结果,返回结果的承诺将限制其用途。 usefetch是nuxt compososable,它可以返回承诺,并且似乎是用于在NUXT Lifecycle钩中使用的,而Uselazyfetch是通用的VUE合并。

这在,结果的属性是参考,因此具有反应性。如果它是用自定义组合包装的,则uselazyfetch的结果需要通过vue Composition API组成,例如,例如当前操作的状态。

usefetchcookiesuseapi需要更改为常规的组合。

export const useToken = () => {
    const data = ref(null);
    const error = ref(null);
    const pending = ref(true);
    const token = useCookie(csrf_cookie).value;

    if (!token) {
      const result = useLazyFetch("/backend/sanctum/csrf-cookie", {
        credentials: "include" 
      });

      watch(result.pending, (val) => {
        pending.value = val;

        if (!val)
          data.value = useCookie(csrf_cookie).value;
      });

      watch(result.error, (val) => {
        error.value = val;
      });
    } else {
      pending.value = false;
      data.value = useCookie(csrf_cookie).value;
    }

    return { data, error, pending };
};

export const useApi = (url: string, options?: FetchOptions, pick?: any) => {
    const data = ref(null);
    const error = ref(null);
    const pending = ref(true);
    const refresh = () => fetchResult.value?.refresh();
    
    const fetchResultRef = ref(null);

    const tokenResult = useToken();

      watch(tokenResult.data, (token) => {
        if (!token)
          return;

        const headers = ...;
        const opts = ...;    
        fetchResultRef.value = useLazyFetch(`/backend/api${url}`, {
            server: false,
            credentials: "include",
            headers,
            ...opts,
            pick: pick
        });
      });

      watch([
        tokenResult.pending,
        () => fetchResultRef.value?.pending ?? true
      ], ([tokenPending, fetchPending]) => {
        pending.value = tokenPending || fetchPending;
      });

      watch([
        tokenResult.error,
        () => fetchResultRef.value?.error ?? null
      ], ([tokenError, fetchError]) => {
        error.value = tokenError || fetchError;
      });

      watch(() => fetchResultRef.value?.data ?? null, (value) => {
        data.value = value;
      });

      return { data, error, pending, refresh };
};

请注意,在此实施中,usecookie结果是反应性的,但反应性被丢弃,因此refresh usetoken 仍然未使用。 uselazyfetch即使名称也立即执行请求,因此需要将其呼叫推迟到标题可用为止。它可以在设置函数后异步称为,这是通过其实现允许的。

It's incorrect to call a composable in onMounted without a specific purpose. Vue composables are generally to be used directly in setup function, so a result could be accessed immediately. Whether it's possible to use them in other places depends on their implementation.

In case a composable involves asynchronous side effects, it's supposed to return reactive result, returning a promise of a result would limit its uses. useFetch is Nuxt composable that returns a promise and seems to be intended for the use in Nuxt lifecycle hooks, while useLazyFetch is generic Vue composable.

This is shown in the usage of useLazyFetch, properties of a result are refs and so are reactive. In case it's wrapped with custom composable, a result from useLazyFetch needs to be composed by means of Vue composition API, e.g. pending should reflect the overall state of a current operation.

Both useFetchCookies and useApi need to be changed to be conventional composables.

export const useToken = () => {
    const data = ref(null);
    const error = ref(null);
    const pending = ref(true);
    const token = useCookie(csrf_cookie).value;

    if (!token) {
      const result = useLazyFetch("/backend/sanctum/csrf-cookie", {
        credentials: "include" 
      });

      watch(result.pending, (val) => {
        pending.value = val;

        if (!val)
          data.value = useCookie(csrf_cookie).value;
      });

      watch(result.error, (val) => {
        error.value = val;
      });
    } else {
      pending.value = false;
      data.value = useCookie(csrf_cookie).value;
    }

    return { data, error, pending };
};

export const useApi = (url: string, options?: FetchOptions, pick?: any) => {
    const data = ref(null);
    const error = ref(null);
    const pending = ref(true);
    const refresh = () => fetchResult.value?.refresh();
    
    const fetchResultRef = ref(null);

    const tokenResult = useToken();

      watch(tokenResult.data, (token) => {
        if (!token)
          return;

        const headers = ...;
        const opts = ...;    
        fetchResultRef.value = useLazyFetch(`/backend/api${url}`, {
            server: false,
            credentials: "include",
            headers,
            ...opts,
            pick: pick
        });
      });

      watch([
        tokenResult.pending,
        () => fetchResultRef.value?.pending ?? true
      ], ([tokenPending, fetchPending]) => {
        pending.value = tokenPending || fetchPending;
      });

      watch([
        tokenResult.error,
        () => fetchResultRef.value?.error ?? null
      ], ([tokenError, fetchError]) => {
        error.value = tokenError || fetchError;
      });

      watch(() => fetchResultRef.value?.data ?? null, (value) => {
        data.value = value;
      });

      return { data, error, pending, refresh };
};

Notice that in this implementation useCookie result is reactive but the reactivity is discarded, and so refresh in useToken remains unused. useLazyFetch does a request immediately, despite the name, so its call needs to be postponed until headers are available. It can be called asynchronously after setup function, this is allowed by its implementation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文