Skip to content

Commit

Permalink
fix: change usage
Browse files Browse the repository at this point in the history
  • Loading branch information
JOU-amjs committed Sep 21, 2023
1 parent 79281d3 commit f6c01a6
Show file tree
Hide file tree
Showing 10 changed files with 101 additions and 101 deletions.
26 changes: 13 additions & 13 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
"@vue/server-renderer": "^3.3.4",
"@vue/vue2-jest": "^29.2.6",
"@vue/vue3-jest": "^29.2.6",
"alova": "^2.12.0",
"alova": "^2.12.1",
"babel-jest": "^29.5.0",
"commitizen": "^4.3.0",
"commitlint": "^17.5.1",
Expand Down
17 changes: 5 additions & 12 deletions src/mapAlovaHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,25 +31,18 @@ export default <GR extends UseHookCallers>(mapGetter: UseHookMapGetter<GR>) => {

// 在created阶段遍历发送请求
for (const dataKey in hookMapper) {
const [useHook, ...params] = hookMapper[dataKey],
lastParam = params[params.length - 1];
myAssert(typeof useHook === 'function', 'use hook function must be a function');

// 为了将vue对象和dataKey传入alova内部,如果未传入config则创建一个
let config = {} as Record<string, any>;
if (isPlainObject(lastParam)) {
config = lastParam;
} else {
params.push(config);
}
// 可以在useHookReturns中通过_$c获取useHook的config对象引用,将vue对象和dataKey传入alova内部
const useHookReturns = hookMapper[dataKey],
config = useHookReturns._$c || {};
delete useHookReturns._$c;
config.dataKey = dataKey;
config.component = vm;

// 不设置set函数,禁止覆盖use hook对应的对象
Object.defineProperty(vm, dataKey, {
get: () => (vm as any)[vueComponentAlovaHookStateKey][dataKey] || {}
});
const [states, fns] = splitStatesAndFn(useHook(...params));
const [states, fns] = splitStatesAndFn(useHookReturns);
if (vm.$set) {
// vue2
vm.$set((vm as any)[vueComponentAlovaHookStateKey], dataKey, states);
Expand Down
61 changes: 32 additions & 29 deletions src/stateHook.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,35 +10,38 @@ export default {
});
},
effectRequest({ handler, removeStates, immediate, watchingStates }, { c: useHookConfig }) {
const { $, $options } = useHookConfig.component;
let componentUnmountedFns = [];
if ($) {
/* c8 ignore start */
// vue3,它将在npm run test:vue3中测试到
// um为生命周期unmounted,它保存在了$中
// 动态注入生命周期函数,组件卸载时移除对应状态
componentUnmountedFns = $.um = $.um || [];
/* c8 ignore stop */
} else {
// vue2为destroyed,生命周期保存在了$options中
const lifecycleContext = $options.__proto__;
componentUnmountedFns = lifecycleContext.destroyed = lifecycleContext.destroyed || [];
}
componentUnmountedFns.push(removeStates);
immediate && handler();
let timer: NodeJS.Timeout | void;
(watchingStates || []).forEach((state, i) => {
useHookConfig.component.$watch(
state,
() => {
timer && clearTimeout(timer);
timer = setTimeout(() => {
handler(i);
timer = undefined;
});
},
{ deep: true }
);
// 需要异步执行,在mapAlovaHook中对config注入component和dataKey
setTimeout(() => {
const { $, $options } = useHookConfig.component;
let componentUnmountedFns = [];
if ($) {
/* c8 ignore start */
// vue3,它将在npm run test:vue3中测试到
// um为生命周期unmounted,它保存在了$中
// 动态注入生命周期函数,组件卸载时移除对应状态
componentUnmountedFns = $.um = $.um || [];
/* c8 ignore stop */
} else {
// vue2为destroyed,生命周期保存在了$options中
const lifecycleContext = $options.__proto__;
componentUnmountedFns = lifecycleContext.destroyed = lifecycleContext.destroyed || [];
}
componentUnmountedFns.push(removeStates);
immediate && handler();
let timer: NodeJS.Timeout | void;
(watchingStates || []).forEach((state, i) => {
useHookConfig.component.$watch(
state,
() => {
timer && clearTimeout(timer);
timer = setTimeout(() => {
handler(i);
timer = undefined;
});
},
{ deep: true }
);
});
});
}
} as StatesHook<any, any>;
2 changes: 1 addition & 1 deletion test/components/TestFetcher.vue
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export default {
},
mixins: mapAlovaHook(function () {
return {
testFetcher: [useFetcher]
testFetcher: useFetcher()
};
}),
emits: ['success', 'error', 'complete'],
Expand Down
16 changes: 6 additions & 10 deletions test/components/TestRequest.vue
Original file line number Diff line number Diff line change
Expand Up @@ -29,17 +29,13 @@ export default {
},
mixins: mapAlovaHook(function () {
return {
testRequest: [
useRequest,
this.method,
{
immediate: this.immediate,
initialData: {},
managedStates: {
extraData: 1
}
testRequest: useRequest(this.method, {
immediate: this.immediate,
initialData: {},
managedStates: {
extraData: 1
}
]
})
// testRequest: useRequest((arg1, arg2) => Get, {})
};
}),
Expand Down
17 changes: 8 additions & 9 deletions test/components/TestWatcher.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,14 @@ export default {
},
mixins: mapAlovaHook(function () {
return {
testWatcher: [
useWatcher,
() => this.methodHandler(this.state1, this.state2.v),
['state1', 'state2.v'],
{
immediate: this.immediate,
initialData: {}
}
]
testWatcher: useWatcher(
() => this.methodHandler(this.state1, this.state2.v),
['state1', 'state2.v'],
{
immediate: this.immediate,
initialData: {}
}
),
};
}),
data() {
Expand Down
24 changes: 13 additions & 11 deletions test/mockData.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createAlovaMockAdapter, defineMock } from '@alova/mock';
import { defineMock } from '@alova/mock';
import { createAlova } from 'alova';
import GlobalFetch from 'alova/GlobalFetch';
import { VueOptionsStateHook } from '../src';

const mockData = defineMock({
Expand All @@ -18,14 +19,15 @@ export const alovaInst = createAlova({
baseURL: 'http://example.com',
statesHook: VueOptionsStateHook,
localCache: null,
requestAdapter: createAlovaMockAdapter([mockData], {
delay: 50,
onMockResponse(response) {
return {
headers: {},
response: response.body
};
},
mockRequestLogger: false
})
requestAdapter: GlobalFetch()
// requestAdapter: createAlovaMockAdapter([mockData], {
// delay: 50,
// onMockResponse(response) {
// return {
// headers: {},
// response: response.body
// };
// },
// mockRequestLogger: false
// })
});
29 changes: 19 additions & 10 deletions test/useRequest.spec.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,36 @@
import '@testing-library/jest-dom';
import { fireEvent, render, screen, waitFor } from '@testing-library/vue';
import { useRequest } from 'alova';
import { mapAlovaHook } from '../src';
import TestRequest from './components/TestRequest.vue';
import { alovaInst } from './mockData';
import { eventObj, untilCbCalled } from './utils';

const ee = useRequest(alovaInst.Get<number>('/'), {
immediate: false
});

ee.loading;

const aa = mapAlovaHook(function () {
return {
test1: useRequest(alovaInst.Get<number>('/'), {
immediate: false
})
};
});

type bb = ReturnType<(typeof aa)[0]['data']>['test1'];
type cc = (typeof aa)[0]['methods'];

describe('vue options request hook', () => {
test('must return object which contains use hook function and params', async () => {
let mixins = mapAlovaHook(function () {
const mixins = mapAlovaHook(function () {
return [];
} as any);
expect(() => {
mixins[0].created.call({});
}).toThrow('expect receive an object which contains use hook return values');

mixins = mapAlovaHook(function () {
return {
test1: ['string', 1, 2]
};
} as any);
expect(() => {
mixins[0].created.call({});
}).toThrow('use hook function must be a function');
});

test('the callback of mapAlovaHook can access context in both this and the first param', async () => {
Expand Down
8 changes: 3 additions & 5 deletions typings/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { StatesHook } from 'alova';

type UseHookCallers = Record<string, [(...args: any[]) => any, ...any[]]>;
type UseHookCallers = Record<string, Record<string, any>>;
type UseHookMapGetter<GR extends UseHookCallers> = (this: Vue, context: Vue) => GR;

type PickFunction<T extends Record<string, any>, U = true> = Pick<
Expand All @@ -19,14 +19,12 @@ type FlattenObjectKeys<T extends Record<string, unknown>, K = keyof T> = K exten
interface VueHookMapperMixin<GR extends UseHookCallers> {
created(): void;
data(): {
[K in keyof GR]: PickFunction<ReturnType<GR[K][0]>, false>;
[K in keyof GR]: PickFunction<GR[K], false>;
} & {
ALOVA_USE_HOOK_STATES$__: Record<string, any>;
};
methods: PickFunction<{
[K in FlattenObjectKeys<{
[K in keyof GR]: ReturnType<GR[K][0]>;
}>]: K extends `${infer P}$${infer S}` ? ReturnType<GR[P][0]>[S] : never;
[K in FlattenObjectKeys<GR>]: K extends `${infer P}$${infer S}` ? GR[P][S] : never;
}>;
}

Expand Down

0 comments on commit f6c01a6

Please sign in to comment.