Skip to content

Commit

Permalink
feat(useLoadMore): refactor refresh and cancel of useLoadMore #36
Browse files Browse the repository at this point in the history
  • Loading branch information
John60676 committed Apr 19, 2021
1 parent 66b3198 commit 7c34351
Show file tree
Hide file tree
Showing 2 changed files with 336 additions and 9 deletions.
284 changes: 284 additions & 0 deletions src/__tests__/load-more.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -429,6 +429,290 @@ describe('useLoadMore', () => {
}
});

test('refresh should work, case: 1', async () => {
const wrapper = shallowMount(
defineComponent({
setup() {
const {
dataList,
loadingMore,
loading,
loadMore,
refresh,
refreshing,
} = useLoadMore(normalRequest);
return () => (
<div>
<div class="dataList">{dataList.value.length || 0}</div>
<div class="loadingMore">{`${loadingMore.value}`}</div>
<div class="loading">{`${loading.value}`}</div>
<div class="refreshing">{`${refreshing.value}`}</div>
<div
class="loadMore"
onClick={() => {
loadMore();
}}
/>
<div
class="refresh"
onClick={() => {
refresh();
}}
/>
</div>
);
},
}),
);

const dataListEl = wrapper.find('.dataList');
const loadingMoreEl = wrapper.find('.loadingMore');
const loadingEl = wrapper.find('.loading');
const loadMoreEl = wrapper.find('.loadMore');
const refreshEl = wrapper.find('.refresh');
const refreshingEl = wrapper.find('.refreshing');

expect(loadingEl.text()).toBe('true');
expect(refreshingEl.text()).toBe('false');
await waitForTime(1000);
expect(refreshingEl.text()).toBe('false');
expect(loadingEl.text()).toBe('false');
expect(dataListEl.text()).toBe('10');
expect(loadingMoreEl.text()).toBe('false');

for (let index = 1; index <= 5; index++) {
await loadMoreEl.trigger('click');
expect(loadingMoreEl.text()).toBe('true');
expect(loadingEl.text()).toBe('true');
expect(refreshingEl.text()).toBe('false');
await waitForTime(1000);
expect(loadingEl.text()).toBe('false');
expect(loadingMoreEl.text()).toBe('false');
expect(refreshingEl.text()).toBe('false');
expect(dataListEl.text()).toBe(`${10 + index * 10}`);
}

expect(dataListEl.text()).toBe('60');
expect(loadingMoreEl.text()).toBe('false');
expect(loadingEl.text()).toBe('false');
expect(refreshingEl.text()).toBe('false');

await refreshEl.trigger('click');
expect(dataListEl.text()).toBe('60');
expect(loadingMoreEl.text()).toBe('false');
expect(loadingEl.text()).toBe('true');
expect(refreshingEl.text()).toBe('true');

await waitForTime(1000);
expect(dataListEl.text()).toBe('10');
expect(loadingMoreEl.text()).toBe('false');
expect(loadingEl.text()).toBe('false');
expect(refreshingEl.text()).toBe('false');
});

test('refresh should work, case: 2', async () => {
const wrapper = shallowMount(
defineComponent({
setup() {
const {
dataList,
loadingMore,
loading,
refresh,
refreshing,
} = useLoadMore(normalRequest);
return () => (
<div>
<div class="dataList">{dataList.value.length || 0}</div>
<div class="loadingMore">{`${loadingMore.value}`}</div>
<div class="loading">{`${loading.value}`}</div>
<div class="refreshing">{`${refreshing.value}`}</div>
<div
class="refresh"
onClick={() => {
refresh();
}}
/>
</div>
);
},
}),
);

const dataListEl = wrapper.find('.dataList');
const loadingMoreEl = wrapper.find('.loadingMore');
const loadingEl = wrapper.find('.loading');
const refreshEl = wrapper.find('.refresh');
const refreshingEl = wrapper.find('.refreshing');

expect(loadingEl.text()).toBe('true');
expect(refreshingEl.text()).toBe('false');
expect(loadingMoreEl.text()).toBe('false');
await refreshEl.trigger('click');
expect(loadingEl.text()).toBe('true');
expect(refreshingEl.text()).toBe('true');
expect(loadingMoreEl.text()).toBe('false');
await waitForTime(1000);
expect(dataListEl.text()).toBe('10');
});

test('cancel should work, case: 1', async () => {
const wrapper = shallowMount(
defineComponent({
setup() {
const {
dataList,
loadingMore,
loading,
loadMore,
refresh,
refreshing,
cancel,
reload,
} = useLoadMore(normalRequest);
return () => (
<div>
<div class="dataList">{dataList.value.length || 0}</div>
<div class="loadingMore">{`${loadingMore.value}`}</div>
<div class="loading">{`${loading.value}`}</div>
<div class="refreshing">{`${refreshing.value}`}</div>
<div
class="loadMore"
onClick={() => {
loadMore();
}}
/>
<div
class="refresh"
onClick={() => {
refresh();
}}
/>
<div
class="cancel"
onClick={() => {
cancel();
}}
/>
<div
class="reload"
onClick={() => {
reload();
}}
/>
</div>
);
},
}),
);

const dataListEl = wrapper.find('.dataList');
const loadingMoreEl = wrapper.find('.loadingMore');
const loadingEl = wrapper.find('.loading');
const loadMoreEl = wrapper.find('.loadMore');
const refreshEl = wrapper.find('.refresh');
const refreshingEl = wrapper.find('.refreshing');
const cancelEl = wrapper.find('.cancel');
const reloadEl = wrapper.find('.reload');

expect(loadingEl.text()).toBe('true');
expect(refreshingEl.text()).toBe('false');
expect(loadingMoreEl.text()).toBe('false');
await waitForTime(1000);
expect(loadingEl.text()).toBe('false');
expect(dataListEl.text()).toBe('10');
expect(loadingMoreEl.text()).toBe('false');

// trigger loadMore
await loadMoreEl.trigger('click');
expect(loadingEl.text()).toBe('true');
expect(loadingMoreEl.text()).toBe('true');
expect(refreshingEl.text()).toBe('false');
await waitForTime(100);
// trigger cancel
await cancelEl.trigger('click');
expect(loadingEl.text()).toBe('false');
expect(loadingMoreEl.text()).toBe('false');
expect(refreshingEl.text()).toBe('false');
expect(dataListEl.text()).toBe('10');

// trigger refresh
await refreshEl.trigger('click');
expect(loadingEl.text()).toBe('true');
expect(loadingMoreEl.text()).toBe('false');
expect(refreshingEl.text()).toBe('true');
await waitForTime(100);
// trigger cancel
await cancelEl.trigger('click');
expect(loadingEl.text()).toBe('false');
expect(loadingMoreEl.text()).toBe('false');
expect(refreshingEl.text()).toBe('false');
expect(dataListEl.text()).toBe('10');

// trigger reload
await reloadEl.trigger('click');
expect(loadingEl.text()).toBe('true');
expect(loadingMoreEl.text()).toBe('false');
expect(refreshingEl.text()).toBe('false');
await waitForTime(100);
// trigger cancel
await cancelEl.trigger('click');
expect(loadingEl.text()).toBe('false');
expect(loadingMoreEl.text()).toBe('false');
expect(refreshingEl.text()).toBe('false');
expect(dataListEl.text()).toBe('0');
});

test('cancel should work, case: 2', async () => {
const wrapper = shallowMount(
defineComponent({
setup() {
const {
dataList,
loadingMore,
loading,
refreshing,
cancel,
} = useLoadMore(normalRequest);
return () => (
<div>
<div class="dataList">{dataList.value.length || 0}</div>
<div class="loadingMore">{`${loadingMore.value}`}</div>
<div class="loading">{`${loading.value}`}</div>
<div class="refreshing">{`${refreshing.value}`}</div>
<div
class="cancel"
onClick={() => {
cancel();
}}
/>
</div>
);
},
}),
);

const dataListEl = wrapper.find('.dataList');
const loadingMoreEl = wrapper.find('.loadingMore');
const loadingEl = wrapper.find('.loading');
const refreshingEl = wrapper.find('.refreshing');
const cancelEl = wrapper.find('.cancel');

expect(loadingEl.text()).toBe('true');
expect(refreshingEl.text()).toBe('false');
expect(loadingMoreEl.text()).toBe('false');

// trigger cancel
await cancelEl.trigger('click');
expect(loadingEl.text()).toBe('false');
expect(refreshingEl.text()).toBe('false');
expect(loadingMoreEl.text()).toBe('false');
expect(dataListEl.text()).toBe('0');

await waitForTime(1000);
expect(dataListEl.text()).toBe('0');
});

test('useLoadMore when request error', async () => {
const wrapper = shallowMount(
defineComponent({
Expand Down
61 changes: 52 additions & 9 deletions src/useLoadMore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,17 @@ import get from 'lodash/get';
import generateService from './core/utils/generateService';
import { isFunction } from './core/utils';
import { ServiceParams } from './core/utils/types';
import omit from 'lodash/omit';

export interface LoadMoreResult<R, P extends unknown[], LR extends unknown[]>
extends Omit<BaseResult<R, P>, 'queries'> {
extends Omit<BaseResult<R, P>, 'queries' | 'refresh'> {
dataList: Ref<LR>;
noMore: Ref<boolean>;
loadingMore: Ref<boolean>;
refreshing: Ref<boolean>;
loadMore: () => void;
reload: () => void;
refresh: () => void;
}

export type LoadMoreExtendsOption = {
Expand Down Expand Up @@ -104,13 +107,19 @@ function useLoadMore<R, P extends unknown[], FR, LR extends unknown[]>(
throw new Error('useLoadMore does not support concurrent request');
}

const refreshing = ref(false);
const loadingMore = ref(false);
const increaseQueryKey = ref(0);
const { data, params, queries, run, reset, ...rest } = useAsyncQuery<
R,
P,
FR
>(promiseQuery, {
const initailIncreaseQueryKey = 0;
const increaseQueryKey = ref(initailIncreaseQueryKey);
const {
data,
params,
queries,
run,
reset,
cancel: _cancel,
...rest
} = useAsyncQuery<R, P, FR>(promiseQuery, {
...restOptions,
onSuccess: (...p) => {
loadingMore.value = false;
Expand Down Expand Up @@ -161,26 +170,60 @@ function useLoadMore<R, P extends unknown[], FR, LR extends unknown[]>(
run(...mergerParams);
};

const unmountQueries = () => {
Object.keys(queries).forEach(key => {
if (key !== initailIncreaseQueryKey.toString()) {
queries[key].cancel();
queries[key].unmount();
delete queries[key];
}
});
};

const refresh = async () => {
refreshing.value = true;
const latestKey = increaseQueryKey.value - 1;
const key =
latestKey < initailIncreaseQueryKey ? initailIncreaseQueryKey : latestKey;

latestData.value = queries[key].data;
increaseQueryKey.value = initailIncreaseQueryKey;
const [, ...restParams] = params.value;
const mergerParams = [undefined, ...restParams] as any;
await run(...mergerParams);
unmountQueries();
refreshing.value = false;
};

const reload = () => {
reset();
increaseQueryKey.value = 0;
increaseQueryKey.value = initailIncreaseQueryKey;
latestData.value = undefined;
const [, ...restParams] = params.value;
const mergerParams = [undefined, ...restParams] as any;
run(...mergerParams);
};

const cancel = () => {
_cancel();
loadingMore.value = false;
refreshing.value = false;
};

return {
data: latestData,
dataList: dataList,
params,
noMore,
loadingMore,
refreshing,
run,
reload,
loadMore,
reset,
...rest,
refresh,
cancel,
...omit(rest, ['refresh']),
};
}

Expand Down

0 comments on commit 7c34351

Please sign in to comment.