From 0399d9b7ecabb7a2f25de14df68690f830bcbe45 Mon Sep 17 00:00:00 2001 From: "javier.brea" Date: Mon, 16 Nov 2020 19:42:42 +0100 Subject: [PATCH 1/2] feat(#105): Supports passing options to cleanCache methods in usePolling and withPolling --- CHANGELOG.md | 4 +++ README.md | 26 ++++++++++++++---- package-lock.json | 2 +- package.json | 2 +- sonar-project.properties | 2 +- src/usePolling.js | 31 ++++++++++++++++------ src/withDataProvider.js | 4 +-- test/usePolling.spec.js | 55 ++++++++++++++++++++++++++++++++++++-- test/withPolling.spec.js | 57 ++++++++++++++++++++++++++++++++++++++-- 9 files changed, 161 insertions(+), 22 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 167614e..85b125a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,10 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ### Fixed ### Removed +## [1.5.0] - 2020-11-16 +### Added +- feat: Supports passing options to cleanCache methods in usePolling and withPolling + ## [1.4.0] - 2020-11-09 ### Added - feat(hocs): Add withDataLoadedError, withDataLoadingError, withDataLoadingErrorComponents, withDataLoadedErrorComponents diff --git a/README.md b/README.md index ce5e6cd..8d751c4 100644 --- a/README.md +++ b/README.md @@ -190,7 +190,7 @@ const BooksList = () => { }; ``` -### `usePolling(provider, [interval])` +### `usePolling(provider, [interval/options], [options])` Triggers `cleanDependenciesCache` method of the provider each `interval` miliseconds while the component is "alive". It can be used in multiple components at the same time for the same provider. In that case, the used interval will be the lower one, and it will be recalculated each time a component is added or removed. @@ -199,9 +199,10 @@ This hook can also be used with [Data Provider selectors][data-provider-selector #### Arguments * `provider` _(Object)_: [Data Provider][data-provider] provider or selector instance. -* `interval` _(Object)_: Interval in miliseconds to clean the provider dependencies cache. Default is 5000. +* `interval` _(Number)_: Interval in miliseconds to clean the provider dependencies cache. Default is 5000. +* `options` _(Object)_: Options object that will be passed as is to the `cleanCache` method of providers or `cleanDependenciesCache` method of selectors. Check the [data-provider API documentation](https://www.data-provider.org/docs/api-providers-and-selectors-methods) for further info. Options can be defined as second argument as well if interval is omitted. -#### Example +#### Examples ```jsx import { useData, usePolling } from "@data-provider/react"; @@ -215,6 +216,20 @@ const BooksList = () => { }; ``` +```jsx +import { useData, usePolling } from "@data-provider/react"; + +import { booksAndAuthors, books } from "../data/books"; + +const BooksList = () => { + const data = useData(books); + usePolling(booksAndAuthors, { + except: [books] + }); + // Do your stuff here. booksAndAuthors selector dependencies will fetched again from server every 3 seconds, except the "books" provider. +}; +``` + ## HOCs ### `withDataLoadingError(provider, [customPropertiesNames])(Component)` @@ -430,14 +445,15 @@ const BooksList = ({ booksError }) => { export default withError(books, "booksError")(BooksList); ``` -### `withPolling(provider, [interval])(Component)` +### `withPolling(provider, [interval/options], [options])(Component)` This High Order Component works as the hook `usePolling` described above. #### Arguments * `provider` _(Object)_: [Data Provider][data-provider] provider or selector instance, or a function as described in the [withDataLoadingError HOC docs](#withdataloadingerrorprovider-custompropertiesnamescomponent) -* `interval` _(Object)_: Interval in miliseconds to clean the provider dependencies cache. Default is 5000. +* `interval` _(Number)_: Interval in miliseconds to clean the provider dependencies cache. Default is 5000. +* `options` _(Object)_: Options object that will be passed as is to the `cleanCache` method of providers or `cleanDependenciesCache` method of selectors. Check the [data-provider API documentation](https://www.data-provider.org/docs/api-providers-and-selectors-methods) for further info. Options can be defined as second argument as well if interval is omitted. #### Example diff --git a/package-lock.json b/package-lock.json index e20736c..3e8c58e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@data-provider/react", - "version": "1.4.0", + "version": "1.5.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 410a295..474c87a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@data-provider/react", - "version": "1.4.0", + "version": "1.5.0", "description": "React bindings for @data-provider", "keywords": [ "data-provider", diff --git a/sonar-project.properties b/sonar-project.properties index 2302329..4e4f3ef 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1,6 +1,6 @@ sonar.organization=data-provider sonar.projectKey=data-provider-react -sonar.projectVersion=1.4.0 +sonar.projectVersion=1.5.0 sonar.sources=src,test sonar.exclusions=node_modules/** diff --git a/src/usePolling.js b/src/usePolling.js index f44527c..7d2b8e5 100644 --- a/src/usePolling.js +++ b/src/usePolling.js @@ -1,10 +1,12 @@ -import { useEffect } from "react"; +import { useEffect, useMemo } from "react"; +const DEFAULT_INTERVAL_TIME = 5000; const pollingProviders = {}; class PollingHandler { - constructor(provider, intervalTime) { + constructor(provider, intervalTime, options) { provider.cleanCache(); + this._options = options; this._provider = provider; this._id = provider.id; this._clients = 1; @@ -16,7 +18,7 @@ class PollingHandler { _setInterval() { this._interval = setInterval(() => { - this._provider.cleanDependenciesCache(); + this._provider.cleanDependenciesCache(this._options); }, this._currentIntervalTime); } @@ -55,19 +57,32 @@ class PollingHandler { } } -export const usePolling = (provider, intervalTime = 5000) => { +export const usePolling = (provider, intervalTimeOrOptions, options = {}) => { + const [intervalTimeToUse, optionsToUse] = useMemo(() => { + if (typeof intervalTimeOrOptions === "undefined") { + return [DEFAULT_INTERVAL_TIME, options]; + } else if (typeof intervalTimeOrOptions === "object") { + return [DEFAULT_INTERVAL_TIME, intervalTimeOrOptions]; + } + return [intervalTimeOrOptions, options]; + }, [intervalTimeOrOptions, options]); + useEffect(() => { let clearProviderInterval; if (provider) { if (pollingProviders[provider.id]) { - pollingProviders[provider.id].addClient(intervalTime); + pollingProviders[provider.id].addClient(intervalTimeToUse); } else { - pollingProviders[provider.id] = new PollingHandler(provider, intervalTime); + pollingProviders[provider.id] = new PollingHandler( + provider, + intervalTimeToUse, + optionsToUse + ); } clearProviderInterval = () => { - pollingProviders[provider.id].removeClient(intervalTime); + pollingProviders[provider.id].removeClient(intervalTimeToUse); }; } return clearProviderInterval; - }, [provider, intervalTime]); + }, [provider, intervalTimeToUse]); }; diff --git a/src/withDataProvider.js b/src/withDataProvider.js index 24156b3..1ed50ec 100644 --- a/src/withDataProvider.js +++ b/src/withDataProvider.js @@ -237,10 +237,10 @@ export const withError = (provider, key) => (Component) => { return WithError; }; -export const withPolling = (provider, interval) => (Component) => { +export const withPolling = (provider, interval, options) => (Component) => { const WithPolling = (props) => { const providerToRead = useProvider(provider, props); - usePolling(providerToRead, interval); + usePolling(providerToRead, interval, options); return ; }; hoistNonReactStatics(WithPolling, Component); diff --git a/test/usePolling.spec.js b/test/usePolling.spec.js index 3fe0296..fedf8ce 100644 --- a/test/usePolling.spec.js +++ b/test/usePolling.spec.js @@ -3,7 +3,7 @@ import React, { useState, useEffect } from "react"; import "@testing-library/jest-dom"; import { render, act } from "@testing-library/react"; -import { providers } from "@data-provider/core"; +import { providers, Selector } from "@data-provider/core"; import sinon from "sinon"; import { usePolling, useData } from "../src"; @@ -20,13 +20,14 @@ const wait = (time = 600) => { }; describe("usePolling", () => { - let sandbox, provider, BooksComponent, Component; + let sandbox, provider, BooksComponent, Component, selector; beforeEach(() => { sandbox = sinon.createSandbox(); provider = new MockProvider(BOOKS_ID, { data: BOOKS, }); + selector = new Selector(provider, (result) => result); sandbox.spy(provider, "cleanCache"); }); @@ -136,4 +137,54 @@ describe("usePolling", () => { expect(provider.cleanCache.callCount).toEqual(4); }); }); + + describe("when using except option", () => { + beforeEach(() => { + const OPTIONS = { + except: [provider], + }; + BooksComponent = () => { + const books = useData(selector); + usePolling(selector, 500, OPTIONS); + return ; + }; + + Component = () => ( + + + + ); + }); + + it("should not clean the provider cache as it is defined in except option", async () => { + render(); + await wait(3000); + expect(provider.cleanCache.callCount).toEqual(0); + }); + }); + + describe("when using options as first argument", () => { + beforeEach(() => { + const OPTIONS = { + except: [provider], + }; + BooksComponent = () => { + const books = useData(selector); + usePolling(selector, OPTIONS); + return ; + }; + + Component = () => ( + + + + ); + }); + + it("should not clean the provider cache as it is defined in except option", async () => { + render(); + await wait(8000); + expect(provider.cleanCache.callCount).toEqual(0); + }, 10000); + }); }); diff --git a/test/withPolling.spec.js b/test/withPolling.spec.js index eb5c978..df20070 100644 --- a/test/withPolling.spec.js +++ b/test/withPolling.spec.js @@ -3,7 +3,7 @@ import React, { useState, useEffect } from "react"; import "@testing-library/jest-dom"; import { render, act } from "@testing-library/react"; -import { providers } from "@data-provider/core"; +import { providers, Selector } from "@data-provider/core"; import sinon from "sinon"; import { withPolling, useData } from "../src"; @@ -20,13 +20,14 @@ const wait = (time = 600) => { }; describe("withPolling", () => { - let sandbox, provider, BooksComponent, BooksComponentToRender, Component; + let sandbox, provider, BooksComponent, BooksComponentToRender, Component, selector; beforeEach(() => { sandbox = sinon.createSandbox(); provider = new MockProvider(BOOKS_ID, { data: BOOKS, }); + selector = new Selector(provider, (result) => result); sandbox.spy(provider, "cleanCache"); }); @@ -151,4 +152,56 @@ describe("withPolling", () => { expect(provider.cleanCache.callCount).toEqual(4); }); }); + + describe("when using except option", () => { + beforeEach(() => { + const OPTIONS = { + except: [provider], + }; + BooksComponent = () => { + const books = useData(selector); + return ; + }; + + BooksComponentToRender = withPolling(selector, 500, OPTIONS)(BooksComponent); + + Component = () => ( + + + + ); + }); + + it("should not clean the provider cache as it is defined in except option", async () => { + render(); + await wait(3000); + expect(provider.cleanCache.callCount).toEqual(0); + }); + }); + + describe("when using options as first argument", () => { + beforeEach(() => { + const OPTIONS = { + except: [provider], + }; + BooksComponent = () => { + const books = useData(selector); + return ; + }; + + BooksComponentToRender = withPolling(selector, OPTIONS)(BooksComponent); + + Component = () => ( + + + + ); + }); + + it("should not clean the provider cache as it is defined in except option", async () => { + render(); + await wait(8000); + expect(provider.cleanCache.callCount).toEqual(0); + }, 10000); + }); }); From 67ff5947d49297fb817ffdd6285c6d8319fcbdd8 Mon Sep 17 00:00:00 2001 From: "javier.brea" Date: Mon, 16 Nov 2020 19:47:02 +0100 Subject: [PATCH 2/2] docs(#105): Fix typo --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8d751c4..7225727 100644 --- a/README.md +++ b/README.md @@ -200,7 +200,7 @@ This hook can also be used with [Data Provider selectors][data-provider-selector * `provider` _(Object)_: [Data Provider][data-provider] provider or selector instance. * `interval` _(Number)_: Interval in miliseconds to clean the provider dependencies cache. Default is 5000. -* `options` _(Object)_: Options object that will be passed as is to the `cleanCache` method of providers or `cleanDependenciesCache` method of selectors. Check the [data-provider API documentation](https://www.data-provider.org/docs/api-providers-and-selectors-methods) for further info. Options can be defined as second argument as well if interval is omitted. +* `options` _(Object)_: Options object that will be passed as is to the `cleanCache` method of providers or `cleanDependenciesCache` method of selectors. Check the [data-provider API documentation](https://www.data-provider.org/docs/api-providers-and-selectors-methods) for further info. Options can be defined as second argument if interval is omitted. #### Examples @@ -453,7 +453,7 @@ This High Order Component works as the hook `usePolling` described above. * `provider` _(Object)_: [Data Provider][data-provider] provider or selector instance, or a function as described in the [withDataLoadingError HOC docs](#withdataloadingerrorprovider-custompropertiesnamescomponent) * `interval` _(Number)_: Interval in miliseconds to clean the provider dependencies cache. Default is 5000. -* `options` _(Object)_: Options object that will be passed as is to the `cleanCache` method of providers or `cleanDependenciesCache` method of selectors. Check the [data-provider API documentation](https://www.data-provider.org/docs/api-providers-and-selectors-methods) for further info. Options can be defined as second argument as well if interval is omitted. +* `options` _(Object)_: Options object that will be passed as is to the `cleanCache` method of providers or `cleanDependenciesCache` method of selectors. Check the [data-provider API documentation](https://www.data-provider.org/docs/api-providers-and-selectors-methods) for further info. Options can be defined as second argument if interval is omitted. #### Example