diff --git a/README.md b/README.md index 75c9d27..9fd085d 100644 --- a/README.md +++ b/README.md @@ -222,6 +222,16 @@ const [reqState, request] = useResource( [params], ); +// reactive parameter +const params = reactive({ id: userId }); +const [reqState, request] = useResource( + ({ id }) => ({ + url: `/user/${id}`, + method: "GET", + }), + [params], +); + // options: onCompleted, onError const [reqState] = useResource( () => ({ diff --git a/src/useResource.ts b/src/useResource.ts index a666f79..dc9dc1b 100644 --- a/src/useResource.ts +++ b/src/useResource.ts @@ -13,7 +13,7 @@ import type { } from "./request"; import { useRequest } from "./useRequest"; import type { FullRefArrayItem } from "./utils"; -import { useReducer, unrefs } from "./utils"; +import { hasReactive, useReducer, unrefs } from "./utils"; const REQUEST_CLEAR_MESSAGE = "A new request has been made before completing the last one"; @@ -82,12 +82,14 @@ function getNextState( }; } +export type RequestDepsParameters = + | Parameters + | FullRefArrayItem> + | ComputedRef>; + export function useResource( fn: T, - requestParams?: - | FullRefArrayItem> - | ComputedRef> - | false, + requestParams?: RequestDepsParameters | false, options?: UseResourceOptions, ): UseResourceResult { const [createRequest, { clear }] = useRequest(fn, { @@ -155,6 +157,7 @@ export function useResource( }, { immediate: true, + deep: hasReactive(requestParams), }, ); diff --git a/tests/useResource.test.ts b/tests/useResource.test.ts index 7b8935b..80b885d 100644 --- a/tests/useResource.test.ts +++ b/tests/useResource.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from "vitest"; import { mount, flushPromises } from "@vue/test-utils"; -import { computed, defineComponent, h, ref, unref } from "vue"; +import { computed, defineComponent, h, ref, unref, reactive } from "vue"; import { useResource } from "../src"; import { getAPIFuncs, MOCK_DATA_USER_LIST } from "./setup/mock-request"; @@ -145,7 +145,7 @@ describe("useResource", () => { expect(wrapper.get('[data-t-id="res.isLoading"]').text()).toBe("false"); }); - test("options: ", async () => { + test("options: defaultState", async () => { const Component = defineComponent({ setup() { const [res, request] = useResource(getAPIFuncs(true).user.get, [], { @@ -182,4 +182,55 @@ describe("useResource", () => { ); expect(wrapper.get('[data-t-id="res.isLoading"]').text()).toBe("false"); }); + + test("reactive parameter", async () => { + const Component = defineComponent({ + setup() { + const params = reactive({ id: "1" }); + const [res] = useResource(getAPIFuncs(true).user.get, [params], { + filter: (p) => Boolean(p?.id), + }); + + expect(unref(res).isLoading).toBeTruthy(); + expect(unref(res).data).toBeUndefined(); + expect(unref(res).response).toBeUndefined(); + expect(unref(res).error).toBeUndefined(); + + const handleChangeId = () => { + params.id = "2"; + }; + + return () => + h("div", [ + h("button", { + "data-t-id": "change_id", + onClick: handleChangeId, + }), + h( + "div", + { "data-t-id": "res.data" }, + JSON.stringify(res.value.data), + ), + h("div", { "data-t-id": "res.isLoading" }, res.value.isLoading), + h("div", { "data-t-id": "params.id" }, params.id), + ]); + }, + }); + + const wrapper = mount(Component); + await flushPromises(); + expect(wrapper.get('[data-t-id="res.data"]').text()).toBe( + JSON.stringify(MOCK_DATA_USER_LIST.find((i) => i.id === "1")), + ); + expect(wrapper.get('[data-t-id="res.isLoading"]').text()).toBe("false"); + expect(wrapper.get('[data-t-id="params.id"]').text()).toBe("1"); + + wrapper.get('[data-t-id="change_id"]').trigger("click"); + await flushPromises(); + expect(wrapper.get('[data-t-id="res.data"]').text()).toBe( + JSON.stringify(MOCK_DATA_USER_LIST.find((i) => i.id === "2")), + ); + expect(wrapper.get('[data-t-id="res.isLoading"]').text()).toBe("false"); + expect(wrapper.get('[data-t-id="params.id"]').text()).toBe("2"); + }); });