@jameshclrk/rxdb-hooks
Version:
React hooks for integrating with RxDB
182 lines (181 loc) • 6.97 kB
JavaScript
;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
var react_1 = require("react");
var helpers_1 = require("./helpers");
var ActionType;
(function (ActionType) {
ActionType[ActionType["Reset"] = 0] = "Reset";
ActionType[ActionType["FetchMore"] = 1] = "FetchMore";
ActionType[ActionType["FetchPage"] = 2] = "FetchPage";
ActionType[ActionType["FetchSuccess"] = 3] = "FetchSuccess";
ActionType[ActionType["CountPages"] = 4] = "CountPages";
ActionType[ActionType["QueryChanged"] = 5] = "QueryChanged";
})(ActionType || (ActionType = {}));
var reducer = function (state, action) {
switch (action.type) {
case ActionType.Reset:
return __assign(__assign({}, state), { result: [], isFetching: true, page: 1 });
case ActionType.FetchMore:
return __assign(__assign({}, state), { isFetching: true, page: state.page + 1 });
case ActionType.FetchPage:
return __assign(__assign({}, state), { isFetching: true, page: action.page });
case ActionType.CountPages:
return __assign(__assign({}, state), { pageCount: action.pageCount });
case ActionType.FetchSuccess:
return __assign(__assign({}, state), { result: action.docs, isFetching: false, isExhausted: !action.pageSize
? true
: action.pagination === 'Infinite'
? action.docs.length < state.page * action.pageSize
: false });
case ActionType.QueryChanged:
return __assign(__assign({}, state), { isFetching: true });
/* istanbul ignore next */
default:
return state;
}
};
var getResultArray = function (result, json) {
if (!result) {
return [];
}
if (result instanceof Map) {
return Array.from(result, function (_a) {
var doc = _a[1];
return (json ? doc.toJSON() : doc);
});
}
var resultArray = Array.isArray(result) ? result : [result];
return json ? resultArray.map(function (doc) { return doc.toJSON(); }) : resultArray;
};
var getResultLength = function (result) {
var resultArray = Array.isArray(result) ? result : [result];
return resultArray.length;
};
/**
* Subscribes to specified query and provides results, also providing:
* - state indicators for fetching and list depletion
* - a fetchMore callback function for pagination support
* - a resetList callback function for conveniently reseting list data
*/
function useRxQuery(query, options) {
if (options === void 0) { options = {}; }
var pageSize = options.pageSize, _a = options.pagination, pagination = _a === void 0 ? 'Infinite' : _a, json = options.json;
var initialState = {
result: [],
page: pageSize ? 1 : undefined,
isFetching: true,
isExhausted: false,
pageCount: 0,
};
var _b = (0, react_1.useReducer)(reducer, initialState), state = _b[0], dispatch = _b[1];
var fetchPage = (0, react_1.useCallback)(function (page) {
if (!pageSize || pagination !== 'Traditional') {
return;
}
if (page < 1 || page > state.pageCount) {
return;
}
dispatch({ type: ActionType.FetchPage, page: page });
}, [pageSize, pagination, state.pageCount]);
var fetchMore = (0, react_1.useCallback)(function () {
if (!pageSize || pagination !== 'Infinite') {
return;
}
if (state.isFetching || state.isExhausted) {
return;
}
dispatch({ type: ActionType.FetchMore });
}, [pageSize, pagination, state.isFetching, state.isExhausted]);
var resetList = (0, react_1.useCallback)(function () {
if (!pageSize) {
return;
}
if (state.page === 1) {
return;
}
dispatch({ type: ActionType.Reset });
}, [pageSize, state.page]);
var performQuery = (0, react_1.useCallback)(function (query) {
// avoid re-assigning reference to original query
var _query = query;
if (pageSize && pagination === 'Traditional') {
_query = _query
.skip((state.page - 1) * pageSize)
.limit(pageSize);
}
if (pageSize && pagination === 'Infinite') {
_query = _query.limit(state.page * pageSize);
}
dispatch({
type: ActionType.QueryChanged,
});
// TODO: find more elegant way to resolve type error
// (TS doesn't consider _query.$.subscribe to be callable)
var sub = _query.$.subscribe(function (result) {
var docs = getResultArray(result, json);
dispatch({
type: ActionType.FetchSuccess,
docs: docs,
pagination: pagination,
pageSize: pageSize,
});
});
return function () {
sub.unsubscribe();
};
}, [json, pageSize, pagination, state.page]);
(0, react_1.useEffect)(function () {
if (!query) {
return;
}
if ((0, helpers_1.isRxQuery)(query)) {
return performQuery(query);
}
}, [query, performQuery]);
(0, react_1.useEffect)(function () {
if (!query ||
!pageSize ||
pagination !== 'Traditional' ||
'then' in query) {
return;
}
if ((0, helpers_1.isRxQuery)(query)) {
// Unconvential counting of documents/pages due to missing RxQuery.count():
// https://github.com/pubkey/rxdb/blob/master/orga/BACKLOG.md#rxquerycount
// TODO: find more elegant way to resolve type error
// (TS doesn't consider _query.$.subscribe to be callable)
var countQuerySub_1 = query.$.subscribe(function (result) {
var resultLength = getResultLength(result);
dispatch({
type: ActionType.CountPages,
pageCount: Math.ceil(resultLength / pageSize),
});
});
return function () {
countQuerySub_1.unsubscribe();
};
}
}, [query, pageSize, pagination]);
return {
result: state.result,
isFetching: state.isFetching,
isExhausted: state.isExhausted,
pageCount: state.pageCount,
currentPage: state.page,
fetchPage: fetchPage,
fetchMore: fetchMore,
resetList: resetList,
};
}
exports.default = useRxQuery;