rc-hooks
Version:
React Hooks Library.
125 lines (124 loc) • 7.44 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var react_1 = require("react");
var ut2_1 = require("ut2");
var useAsync_1 = tslib_1.__importDefault(require("../useAsync"));
var useScrollToLower_1 = tslib_1.__importDefault(require("./useScrollToLower"));
var useUpdateEffect_1 = tslib_1.__importDefault(require("../useUpdateEffect"));
/**
* 基于 `useAsync` 扩展,用于管理加载更多的 Hook。
*
* @param {number} [options.threshold=100] 上拉自动加载,距离底部距离阈值。默认 `100`。
* @param {Object | Function} [options.target] 内容的滚动容器,如果存在,则在滚动到底部时,自动触发 `loadMore` 方法。
* @param {Function} [options.isNoMore=()=>false] 判断是否没有更多数据。默认 `()=>false`。
* @param {boolean} [options.autoRun=true] 在初始化时自动执行异步函数。如果设置为 `false`,则需要手动调用 `run` 触发执行。默认 `true`。
* @param {*} [options.initialData] 初始化的 `data`。
* @param {boolean} [options.defaultLoading] 初始化默认 `loading` 值。默认值等于 `autoRun && !loadingDelay`。
* @param {Array} [options.defaultParams] 如果 `autoRun=true` 自动执行 `run` 的默认参数。
* @param {Array} [options.refreshDeps] 在 `autoRun = true` 时,refreshDeps 变化,会执行 `refresh` (重置`current`到第 1 页,并清除之前列表数据,发起请求。)。
* @param {Function} [options.onBefore] 异步函数执行前触发,参数为 `params`。
* @param {Function} [options.onSuccess] 异步函数 `resolve` 时触发,参数为 `data` 和 `params`。
* @param {Function} [options.onError] 异步函数报错时触发,参数为 `error` 和 `params`。
* @param {number} [options.loadingDelay] 设置 `loading` 延迟时间,避免闪烁,单位为毫秒。
* @param {boolean} [options.refreshOnWindowFocus=false] 在屏幕重新获取焦点或重新显示时,是否重新发起请求。如果为 `false`,不会重新发起请求。如果为 `true`,在屏幕重新聚焦或重新显示时,会重新发起请求。默认 `false`。
* @param {number} [options.focusTimespan=5000] 屏幕重新聚焦,重新发起请求时间间隔。需要配置 `refreshOnWindowFocus` 使用。默认 `5000`。
* @param {number} [options.debounceInterval] 防抖间隔,单位为毫秒,设置后,请求进入防抖模式。
* @param {number} [options.throttleInterval] 节流间隔,单位为毫秒,设置后,请求进入节流模式。
* @returns {Object}
* @example
* const { data, error, loading, loadingMore, noMore, loadMore, refresh, cancel } = useLoadMore(asyncFn, options);
*/
function useLoadMore(asyncFn, options) {
var _this = this;
var _a = (options || {}), _b = _a.threshold, threshold = _b === void 0 ? 100 : _b, target = _a.target, _c = _a.isNoMore, isNoMore = _c === void 0 ? function () { return false; } : _c, _d = _a.refreshDeps, refreshDeps = _d === void 0 ? [] : _d, _e = _a.autoRun, autoRun = _e === void 0 ? true : _e, restOptions = tslib_1.__rest(_a, ["threshold", "target", "isNoMore", "refreshDeps", "autoRun"]);
var dataGroup = (0, react_1.useRef)([]); // 缓存之前请求的列表数据
var currentPageRef = (0, react_1.useRef)(1); // 当前页码
var _f = (0, useAsync_1.default)(asyncFn, tslib_1.__assign(tslib_1.__assign({ defaultParams: [
{
current: currentPageRef.current
}
], autoRun: autoRun }, restOptions), { onError: function (err, _params) {
var _a;
// 加载失败并且当前页码大于第一页,页码自减一
if (currentPageRef.current > 1) {
currentPageRef.current -= 1;
}
(_a = restOptions === null || restOptions === void 0 ? void 0 : restOptions.onError) === null || _a === void 0 ? void 0 : _a.call(restOptions, err, _params);
}, __INTERNAL_FORMAT__: function (res) {
dataGroup.current =
currentPageRef.current === 1 ? res.list : dataGroup.current.concat(res.list);
return tslib_1.__assign(tslib_1.__assign({}, res), { list: dataGroup.current });
} })), run = _f.run, data = _f.data, loading = _f.loading, reqCancel = _f.cancel, params = _f.params, reqMutate = _f.mutate, restAsyncReturn = tslib_1.__rest(_f, ["run", "data", "loading", "cancel", "params", "mutate"]);
var noMore = isNoMore ? !loading && isNoMore(data) : false;
var _g = tslib_1.__read(params || []), firstParams = _g[0], restParams = _g.slice(1);
var loadData = (0, react_1.useCallback)(function () {
return run.apply(void 0, [{ current: currentPageRef.current }].concat(restParams));
}, [restParams, run]);
var cancel = (0, react_1.useCallback)(function () {
// 加载中并且当前页码大于第一页,页码自减一
if (loading && currentPageRef.current > 1) {
currentPageRef.current -= 1;
}
reqCancel();
}, [reqCancel, loading]);
/**
* 触发加载更多。
*/
var loadMore = (0, react_1.useCallback)(function () { return tslib_1.__awaiter(_this, void 0, void 0, function () {
return tslib_1.__generator(this, function (_a) {
if (loading || noMore) {
return [2 /*return*/];
}
currentPageRef.current += 1;
return [2 /*return*/, loadData()];
});
}); }, [loading, noMore, loadData]);
var mutate = (0, react_1.useCallback)(function (param) {
var res = typeof param === 'function' ? param(data) : param;
dataGroup.current = (res === null || res === void 0 ? void 0 : res.list) || [];
reqMutate(res);
}, [data, reqMutate]);
var refresh = (0, react_1.useCallback)(function () {
cancel();
currentPageRef.current = 1;
mutate(function (d) { return (tslib_1.__assign(tslib_1.__assign({}, d), { list: [] })); });
return loadData();
}, [cancel, loadData, mutate]);
var scrollMethod = (0, react_1.useCallback)(function () {
if (loading || !target) {
return;
}
return loadMore();
}, [loadMore, target, loading]);
(0, useScrollToLower_1.default)({
target: target,
threshold: threshold,
onScrollLower: scrollMethod
});
(0, useUpdateEffect_1.default)(function () {
if (autoRun && (0, ut2_1.isArray)(refreshDeps) && refreshDeps.length > 0) {
refresh();
}
}, refreshDeps);
return tslib_1.__assign(tslib_1.__assign({}, restAsyncReturn), { loading: loading, data: data, run: run,
/**
* 重置`current`到第 `1` 页,并清除之前列表数据,发起请求。
*/
refresh: refresh, cancel: cancel, mutate: mutate, params: [tslib_1.__assign(tslib_1.__assign({}, firstParams), { current: currentPageRef.current })].concat(restParams),
/**
* 触发加载更多。
*
* 如果没有更多或者正在加载中,返回 `undefined`。
*/
loadMore: loadMore,
/**
* 是否正在加载更多。即加载中并且 `current` 不等于 `1`。
*/
loadingMore: loading && currentPageRef.current > 1,
/**
* 是否没有更多。
*/
noMore: noMore });
}
exports.default = useLoadMore;