UNPKG

@jameshclrk/rxdb-hooks

Version:

React hooks for integrating with RxDB

182 lines (181 loc) 6.97 kB
"use strict"; 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;