├── .all-contributorsrc ├── .babelrc ├── .eslintignore ├── .eslintrc.js ├── .github └── PULL_REQUEST_TEMPLATE.md ├── .gitignore ├── .nvmrc ├── .prettierrc ├── .travis.yml ├── .vscode └── settings.json ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── __mock_data__ └── data.js ├── dist ├── ReactPollingHook.js └── ReactPollingHook.js.map ├── package.json ├── polyfills.js ├── setupTests.js ├── src ├── index.js ├── usePolling.js └── usePolling.test.js ├── webpack.config.js └── yarn.lock /.all-contributorsrc: -------------------------------------------------------------------------------- 1 | { 2 | "projectName": "react-polling-hook", 3 | "projectOwner": "vivek12345", 4 | "repoType": "github", 5 | "repoHost": "https://github.com", 6 | "files": [ 7 | "README.md" 8 | ], 9 | "imageSize": 100, 10 | "commit": true, 11 | "contributors": [ 12 | { 13 | "login": "vivek12345", 14 | "name": "Vivek Nayyar", 15 | "avatar_url": "https://avatars3.githubusercontent.com/u/4931048?v=4", 16 | "profile": "https://www.viveknayyar.in/", 17 | "contributions": [ 18 | "doc", 19 | "code", 20 | "design", 21 | "example" 22 | ] 23 | } 24 | ] 25 | } 26 | -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "loose": true 7 | } 8 | ], 9 | "@babel/preset-react" 10 | ], 11 | "plugins": [ 12 | [ 13 | "@babel/plugin-proposal-class-properties", 14 | { 15 | "loose": true 16 | } 17 | ], 18 | "@babel/plugin-transform-object-assign", 19 | "@babel/plugin-transform-spread" 20 | ], 21 | "env": { 22 | "test": { 23 | "plugins": [ 24 | "@babel/transform-modules-commonjs" 25 | ] 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | webpack.config.js -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | parser: 'babel-eslint', 3 | parserOptions: { 4 | ecmaVersion: 6, 5 | sourceType: 'module', 6 | ecmaFeatures: { 7 | jsx: true, 8 | arrowFunctions: true, 9 | module: true, 10 | experimentalObjectRestSpread: true 11 | } 12 | }, 13 | env: { 14 | browser: true, 15 | node: true, 16 | jest: true, 17 | es6: true 18 | }, 19 | plugins: ['react'], 20 | extends: ['eslint:recommended', 'plugin:react/recommended'], 21 | rules: { 22 | indent: ['error', 2, { SwitchCase: 1 }], 23 | 'linebreak-style': ['error', 'unix'], 24 | quotes: ['error', 'single'], 25 | semi: ['error', 'always'], 26 | 'no-console': ['off'], 27 | 'jsx-quotes': ['error', 'prefer-single'], 28 | 'react/display-name': ['off', { ignoreTranspilerName: false }] 29 | } 30 | }; 31 | -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | 10 | **What kind of change does this PR introduce?** 11 | 12 | 13 | **What is the current behavior?** 14 | 15 | 16 | **What is the new behavior?** 17 | 18 | 19 | 20 | **Checklist**: 21 | 22 | 23 | - [ ] Documentation 24 | - [ ] Tests 25 | - [ ] Ready to be merged 26 | - [ ] Added myself to contributors table 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | 6 | # testing 7 | /coverage 8 | 9 | # production 10 | /lib 11 | 12 | # misc 13 | .DS_Store 14 | .env.local 15 | .env.development.local 16 | .env.test.local 17 | .env.production.local 18 | 19 | npm-debug.log* 20 | yarn-debug.log* 21 | yarn-error.log* 22 | env/properties.env 23 | test-report.xml 24 | *.swp 25 | *.idea 26 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | v8.10.0 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babylon", 3 | "printWidth": 120, 4 | "tabWidth": 2, 5 | "singleQuote": true, 6 | "trailingComma": "none", 7 | "bracketSpacing": true, 8 | "semi": true, 9 | "useTabs": false, 10 | "jsxBracketSameLine": false 11 | } -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | - "v8.10.0" 5 | cache: yarn 6 | branches: 7 | only: 8 | - master 9 | script: 10 | - yarn test -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "editor.fontSize": 12, 3 | "editor.formatOnPaste": true, 4 | "editor.formatOnSave": true, 5 | "prettier.eslintIntegration": true 6 | } -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ## Setting Up the project locally 2 | 3 | To install the project you need to have `yarn` and `node` 4 | 5 | 1. [Fork](https://help.github.com/articles/fork-a-repo/) the project, clone your fork: 6 | 7 | ``` 8 | # Clone your fork 9 | git clone https://github.com//react-polling-hook.git 10 | 11 | # Navigate to the newly cloned directory 12 | cd react-polling-hook 13 | ``` 14 | 15 | 2. `yarn` to install dependencies 16 | 3. `yarn build` to build the UMD and ES bundle of the app 17 | 18 | 19 | > Tip: Keep your `master` branch pointing at the original repository and make 20 | > pull requests from branches on your fork. To do this, run: 21 | > 22 | > ``` 23 | > git remote add upstream https://github.com/vivek12345/react-polling-hook.git 24 | > git fetch upstream 25 | > git branch --set-upstream-to=upstream/master master 26 | > ``` 27 | > 28 | > This will add the original repository as a "remote" called "upstream," 29 | > Then fetch the git information from that remote, then set your local `master` 30 | > branch to use the upstream master branch whenever you run `git pull`. 31 | > Then you can make all of your pull request branches based on this `master` 32 | > branch. Whenever you want to update your version of `master`, do a regular 33 | > `git pull`. 34 | 35 | ## Submitting a Pull Request 36 | 37 | Please go through existing issues and pull requests to check if somebody else is already working on it, we use `someone working on it` label to mark such issues. 38 | 39 | Also, make sure to run the tests and lint the code before you commit your changes. 40 | 41 | ``` 42 | yarn test 43 | yarn lint 44 | ``` 45 | 46 | ## Add yourself as a contributor 47 | 48 | This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome! 49 | 50 | To add yourself to the table of contributors on the `README.md`, please use the 51 | automated script as part of your PR: 52 | 53 | ``` 54 | yarn add-contributor 55 | ``` 56 | 57 | Follow the prompt and commit `.all-contributorsrc` and `README.md` in the PR. 58 | 59 | Thank you for taking the time to contribute! :+1: 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Vivek Nayyar 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🔔 react-polling-hook 2 | [![All Contributors](https://img.shields.io/badge/all_contributors-1-orange.svg?style=flat-square)](#contributors) 3 | 4 | 5 | [![Build Status](https://travis-ci.com/vivek12345/react-polling-hook.svg)](https://travis-ci.com/vivek12345/react-polling-hook) 6 | 7 | > ⚠️ Not yet published on npm and is not being currently developed. If you still need it, please fork the repo. 8 | 9 | Easy to use polling service built with react that uses the new React Hooks(Note: This is an alpha release) 10 | 11 | **Note: Read more about react hooks here [React hooks](https://reactjs.org/docs/hooks-intro.html)** 12 | 13 | ### 🚚 Installation 14 | 15 | ``` 16 | yarn add react-polling-hook 17 | ``` 18 | 19 | or 20 | 21 | ``` 22 | npm i react-polling-hook --save 23 | ``` 24 | 25 | ### ⚡️ Usage 26 | 27 | ```javascript 28 | import React, { Fragment } from 'react'; 29 | import { usePolling } from 'react-polling-hook'; 30 | 31 | const App = () => { 32 | const [isPolling, startPolling, stopPolling] = usePolling({ 33 | url: 'url to poll', 34 | interval: 3000, // in milliseconds(ms) 35 | retryCount: 3, // this is optional 36 | onSuccess: () => console.log('handle success'), 37 | onFailure: () => console.log('handle failure'), // this is optional 38 | method: 'GET', 39 | headers: "headers object", // this is optional 40 | body: JSON.stringify(data) // data to send in a post call. Should be stringified always 41 | }); 42 | 43 | return ( 44 |
45 | {isPolling ? ( 46 | 47 |
Hello I am polling
48 | 49 |
50 | ) : ( 51 | 52 |
Hello I have stopped polling
53 | 54 |
55 | )} 56 |
57 | ); 58 | } 59 | ``` 60 | 61 | ## 📒 Api 62 | 63 | ### 🔔 react-polling-hook 64 | 65 | | Props | Type | Default | Description | 66 | |-------------------------|------------------------|-----------|-----------------------------------------------------------------------------------------------------| 67 | | url | string | null | url/api to poll | 68 | | interval | number | 3000 | Interval of polling | 69 | | retryCount | number | 0 | Number of times to retry when an api polling call fails | 70 | | onSuccess | function | - | Callback function on successful polling. This should return true to continue polling | 71 | | onFailure | function | () => {} | Callback function on failed polling or api failure | 72 | | method | string | GET | HTTP Method of the api to call | 73 | | headers | object | - | Any specific http headers that need to be sent with the request | 74 | | body | object | - | The data that need to be sent in a post/put call 75 | 76 | #### onSuccess (required) 77 | 78 | This function will be called every time the polling service gets a successful response. 79 | You should return true to continue polling and false to stop polling. It has the following signature: 80 | 81 | ```javascript 82 | function onSuccess(response) { 83 | // You can do anything with this response, may be add to an array of some state of your react component 84 | // return true to continue polling 85 | // return false to stop polling 86 | } 87 | ``` 88 | 89 | #### onFailure (not compulsory field) 90 | 91 | This function will be called every time the polling service gets a failure response from the api, it can be 401 or 500 or any failure status code. 92 | You can do some cleaning up of your variables or reseting the state here. 93 | 94 | ```javascript 95 | function onFailure(error) { 96 | // You can log this error to some logging service 97 | // clean up some state and variables. 98 | } 99 | ``` 100 | 101 | ## 👍 Contribute 102 | 103 | Show your ❤️ and support by giving a ⭐. Any suggestions and pull request are welcome ! 104 | 105 | ### 📝 License 106 | 107 | MIT © [viveknayyar](https://github.com/vivek12345) 108 | 109 | ## 👷 TODO 110 | 111 | - [x] Complete README 112 | - [ ] Add Examples and Demo 113 | - [ ] Test Suite 114 | 115 | ## Contributors 116 | 117 | Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)): 118 | 119 | 120 | 121 | | [
Vivek Nayyar](https://www.viveknayyar.in/)
[📖](https://github.com/vivek12345/react-polling-hook/commits?author=vivek12345 "Documentation") [💻](https://github.com/vivek12345/react-polling-hook/commits?author=vivek12345 "Code") [🎨](#design-vivek12345 "Design") [💡](#example-vivek12345 "Examples") | 122 | | :---: | 123 | 124 | 125 | This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome! 126 | -------------------------------------------------------------------------------- /__mock_data__/data.js: -------------------------------------------------------------------------------- 1 | export const continuePollingResponse = { 2 | data: { 3 | data: { 4 | status: 'awaiting_product_selection' 5 | }, 6 | message: 'get session status successfully' 7 | } 8 | }; 9 | -------------------------------------------------------------------------------- /dist/ReactPollingHook.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("react")):"function"==typeof define&&define.amd?define(["react"],t):"object"==typeof exports?exports.ReactPollingHook=t(require("react")):e.ReactPollingHook=t(e.react)}(window,function(e){return function(e){var t={};function r(n){if(t[n])return t[n].exports;var o=t[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,r),o.l=!0,o.exports}return r.m=e,r.c=t,r.d=function(e,t,n){r.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:n})},r.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},r.t=function(e,t){if(1&t&&(e=r(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var n=Object.create(null);if(r.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)r.d(n,o,function(t){return e[t]}.bind(null,o));return n},r.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return r.d(t,"a",t),t},r.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},r.p="",r(r.s=1)}([function(t,r){t.exports=e},function(e,t,r){"use strict";r.r(t);var n=r(0),o=r.n(n);var u=function(e){if(o.a.version.split("-")[0]<"16.7.0")throw new Error("Hooks are only supported in React 16.7.0-alpha release or above");var t=e.url,r=e.interval,u=void 0===r?3e3:r,c=e.retryCount,i=void 0===c?0:c,f=e.onSuccess,a=e.onFailure,l=void 0===a?function(){}:a,s=function(e,t){if(null==e)return{};var r,n,o={},u=Object.keys(e);for(n=0;n=0||(o[r]=e[r]);return o}(e,["url","interval","retryCount","onSuccess","onFailure"]),d=Object(n.useState)(!1),p=d[0],b=d[1],v=Object(n.useRef)(),y=Object(n.useRef)(),j=Object(n.useRef)();if(v.current=p,Object(n.useEffect)(function(){return y.current=!0,m(),function(){y.current=!1,h()}},[]),!t)throw new Error("No url provided to poll. Please provide a config object with the url param set");var O=!!i,h=function(){y.current&&(j.current&&(clearTimeout(j.current),j.current=null),b(!1))},m=function(){b(!0),g()},g=function e(){var r=setTimeout(function(){fetch(t,s).then(function(e){return e.json().then(function(t){return e.ok?t:Promise.reject({status:e.status,data:t})})}).then(f).then(function(t){v.current&&t?e():h()}).catch(function(t){O&&i>0?(l&&l(t),i--,e()):(l&&l(t),h())})},u);j.current=r};return[p,m,h]};r.d(t,"usePolling",function(){return u})}])}); 2 | //# sourceMappingURL=ReactPollingHook.js.map -------------------------------------------------------------------------------- /dist/ReactPollingHook.js.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["webpack://ReactPollingHook/webpack/universalModuleDefinition","webpack://ReactPollingHook/webpack/bootstrap","webpack://ReactPollingHook/external \"react\"","webpack://ReactPollingHook/./src/usePolling.js","webpack://ReactPollingHook/./src/index.js"],"names":["root","factory","exports","module","require","define","amd","window","__WEBPACK_EXTERNAL_MODULE__0__","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","usePolling","config","React","version","split","Error","url","_config$interval","interval","_config$retryCount","retryCount","onSuccess","_config$onFailure","onFailure","api","_objectWithoutPropertiesLoose","_useState","useState","isPolling","togglePolling","persistedIsPolling","useRef","isMounted","poll","current","useEffect","startPolling","stopPolling","shouldRetry","clearTimeout","runPolling","timeoutId","setTimeout","fetch","then","resp","json","data","ok","Promise","reject","status","continuePolling","catch","error","__webpack_exports__","src_usePolling"],"mappings":"CAAA,SAAAA,EAAAC,GACA,iBAAAC,SAAA,iBAAAC,OACAA,OAAAD,QAAAD,EAAAG,QAAA,UACA,mBAAAC,eAAAC,IACAD,QAAA,SAAAJ,GACA,iBAAAC,QACAA,QAAA,iBAAAD,EAAAG,QAAA,UAEAJ,EAAA,iBAAAC,EAAAD,EAAA,OARA,CASCO,OAAA,SAAAC,GACD,mBCTA,IAAAC,KAGA,SAAAC,EAAAC,GAGA,GAAAF,EAAAE,GACA,OAAAF,EAAAE,GAAAT,QAGA,IAAAC,EAAAM,EAAAE,IACAC,EAAAD,EACAE,GAAA,EACAX,YAUA,OANAY,EAAAH,GAAAI,KAAAZ,EAAAD,QAAAC,IAAAD,QAAAQ,GAGAP,EAAAU,GAAA,EAGAV,EAAAD,QA0DA,OArDAQ,EAAAM,EAAAF,EAGAJ,EAAAO,EAAAR,EAGAC,EAAAQ,EAAA,SAAAhB,EAAAiB,EAAAC,GACAV,EAAAW,EAAAnB,EAAAiB,IACAG,OAAAC,eAAArB,EAAAiB,GAA0CK,YAAA,EAAAC,IAAAL,KAK1CV,EAAAgB,EAAA,SAAAxB,GACA,oBAAAyB,eAAAC,aACAN,OAAAC,eAAArB,EAAAyB,OAAAC,aAAwDC,MAAA,WAExDP,OAAAC,eAAArB,EAAA,cAAiD2B,OAAA,KAQjDnB,EAAAoB,EAAA,SAAAD,EAAAE,GAEA,GADA,EAAAA,IAAAF,EAAAnB,EAAAmB,IACA,EAAAE,EAAA,OAAAF,EACA,KAAAE,GAAA,iBAAAF,QAAAG,WAAA,OAAAH,EACA,IAAAI,EAAAX,OAAAY,OAAA,MAGA,GAFAxB,EAAAgB,EAAAO,GACAX,OAAAC,eAAAU,EAAA,WAAyCT,YAAA,EAAAK,UACzC,EAAAE,GAAA,iBAAAF,EAAA,QAAAM,KAAAN,EAAAnB,EAAAQ,EAAAe,EAAAE,EAAA,SAAAA,GAAgH,OAAAN,EAAAM,IAAqBC,KAAA,KAAAD,IACrI,OAAAF,GAIAvB,EAAA2B,EAAA,SAAAlC,GACA,IAAAiB,EAAAjB,KAAA6B,WACA,WAA2B,OAAA7B,EAAA,SAC3B,WAAiC,OAAAA,GAEjC,OADAO,EAAAQ,EAAAE,EAAA,IAAAA,GACAA,GAIAV,EAAAW,EAAA,SAAAiB,EAAAC,GAAsD,OAAAjB,OAAAkB,UAAAC,eAAA1B,KAAAuB,EAAAC,IAGtD7B,EAAAgC,EAAA,GAIAhC,IAAAiC,EAAA,mBClFAxC,EAAAD,QAAAM,2DCEA,IAoFeoC,EApFI,SAAAC,GAEjB,GADgBC,IAAMC,QAAQC,MAAM,KACxB,GAAK,SACf,MAAM,IAAIC,MAAM,mEAHS,IAKrBC,EAAkFL,EAAlFK,IALqBC,EAK6DN,EAA7EO,gBALgB,IAAAD,EAKL,IALKA,EAAAE,EAK6DR,EAA5DS,kBALD,IAAAD,EAKc,EALdA,EAKiBE,EAA4CV,EAA5CU,UALjBC,EAK6DX,EAAjCY,iBAL5B,IAAAD,EAKwC,aALxCA,EAKqDE,sIALrDC,CAK6Dd,GAL7D,wDAAAe,EAMQC,oBAAS,GAArCC,EANoBF,EAAA,GAMTG,EANSH,EAAA,GAQrBI,EAAqBC,mBACrBC,EAAYD,mBACZE,EAAOF,mBAcb,GAZAD,EAAmBI,QAAUN,EAE7BO,oBAAU,WAGR,OAFAH,EAAUE,SAAU,EACpBE,IACO,WACLJ,EAAUE,SAAU,EACpBG,WAKCrB,EACH,MAAM,IAAID,MAAM,kFAGlB,IAAMuB,IAAclB,EAEdiB,EAAc,WACdL,EAAUE,UACRD,EAAKC,UACPK,aAAaN,EAAKC,SAClBD,EAAKC,QAAU,MAEjBL,GAAc,KAIZO,EAAe,WAEnBP,GAAc,GAEdW,KAGIA,EAAa,SAAbA,IACJ,IAAMC,EAAYC,WAAW,WAK3BC,MAAM3B,EAAKQ,GACRoB,KAAK,SAAAC,GACJ,OAAOA,EAAKC,OAAOF,KAAK,SAAAG,GACtB,OAAIF,EAAKG,GACAD,EAEAE,QAAQC,QAASC,OAAQN,EAAKM,OAAQJ,aAIlDH,KAAKvB,GACLuB,KAAK,SAAAQ,GACJtB,EAAmBI,SAAWkB,EAAkBZ,IAAeH,MAEhEgB,MAAM,SAAAC,GACDhB,GAAelB,EAAa,GAC9BG,GAAaA,EAAU+B,GACvBlC,IACAoB,MAEAjB,GAAaA,EAAU+B,GACvBjB,QAGLnB,GACHe,EAAKC,QAAUO,GAGjB,OAAQb,EAAWQ,EAAcC,ICnFnC7D,EAAAQ,EAAAuE,EAAA,+BAAAC","file":"ReactPollingHook.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory(require(\"react\"));\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine([\"react\"], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"ReactPollingHook\"] = factory(require(\"react\"));\n\telse\n\t\troot[\"ReactPollingHook\"] = factory(root[\"react\"]);\n})(window, function(__WEBPACK_EXTERNAL_MODULE__0__) {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 1);\n","module.exports = __WEBPACK_EXTERNAL_MODULE__0__;","import React, { useState, useEffect, useRef } from 'react';\n\nconst usePolling = config => {\n const version = React.version.split('-');\n if (version[0] < '16.7.0') {\n throw new Error('Hooks are only supported in React 16.7.0-alpha release or above');\n }\n let { url, interval = 3000, retryCount = 0, onSuccess, onFailure = () => {}, ...api } = config;\n const [isPolling, togglePolling] = useState(false);\n\n const persistedIsPolling = useRef();\n const isMounted = useRef();\n const poll = useRef();\n\n persistedIsPolling.current = isPolling;\n\n useEffect(() => {\n isMounted.current = true;\n startPolling();\n return () => {\n isMounted.current = false;\n stopPolling();\n };\n }, []);\n\n // if no url specified, throw an error\n if (!url) {\n throw new Error('No url provided to poll. Please provide a config object with the url param set');\n }\n\n const shouldRetry = retryCount ? true : false;\n\n const stopPolling = () => {\n if (isMounted.current) {\n if (poll.current) {\n clearTimeout(poll.current);\n poll.current = null;\n }\n togglePolling(false);\n }\n };\n\n const startPolling = () => {\n // why this does not update state?\n togglePolling(true);\n // call runPolling, which will start timer and call our api\n runPolling();\n };\n\n const runPolling = () => {\n const timeoutId = setTimeout(() => {\n /* onSuccess would be handled by the user of service which would either return true or false\n * true - This means we need to continue polling\n * false - This means we need to stop polling\n */\n fetch(url, api)\n .then(resp => {\n return resp.json().then(data => {\n if (resp.ok) {\n return data;\n } else {\n return Promise.reject({ status: resp.status, data });\n }\n });\n })\n .then(onSuccess)\n .then(continuePolling => {\n persistedIsPolling.current && continuePolling ? runPolling() : stopPolling();\n })\n .catch(error => {\n if (shouldRetry && retryCount > 0) {\n onFailure && onFailure(error);\n retryCount--;\n runPolling();\n } else {\n onFailure && onFailure(error);\n stopPolling();\n }\n });\n }, interval);\n poll.current = timeoutId;\n };\n\n return [isPolling, startPolling, stopPolling];\n};\n\nexport default usePolling;\n","import usePolling from './usePolling';\nexport { usePolling };\n"],"sourceRoot":""} -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "react-polling-hook", 3 | "version": "1.0.0", 4 | "description": "Polling an API made easy with usePolling react hook", 5 | "main": "lib/index.js", 6 | "author": "Vivek Nayyar (https://viveknayyar.in)", 7 | "license": "MIT", 8 | "keywords": [ 9 | "react", 10 | "polling", 11 | "usePolling", 12 | "react-polling-hook" 13 | ], 14 | "files": [ 15 | "lib", 16 | "dist", 17 | "src" 18 | ], 19 | "scripts": { 20 | "start": "webpack-dev-server --config ./webpack.config.dev.js", 21 | "test": "cross-env NODE_ENV=test jest", 22 | "test:watch": "cross-env NODE_ENV=test jest --watch", 23 | "test:coverage": "cross-env NODE_ENV=test jest --coverage && cat ./coverage/lcov.info | coveralls", 24 | "lint": "eslint src/", 25 | "lint:fix": "eslint --fix src/", 26 | "build": "npm run build:es && npm run build:umd", 27 | "build:es": "npm run clean:es && cross-env NODE_ENV=production babel --ignore=src/__tests__ src -d lib", 28 | "build:umd": "npm run clean:umd && cross-env NODE_ENV=production webpack", 29 | "clean:es": "rimraf lib/*", 30 | "clean:umd": "rimraf dist/*", 31 | "prepublish": "npm run lint && npm run test && npm run build", 32 | "contributors:add": "all-contributors add", 33 | "contributors:generate": "all-contributors generate" 34 | }, 35 | "lint-staged": { 36 | "src/**/*.{js,jsx}": [ 37 | "npm run eslint:fix", 38 | "git add" 39 | ], 40 | "src/**/*.{js,jsx,json,css}": [ 41 | "prettier --config .prettierrc --write", 42 | "git add" 43 | ] 44 | }, 45 | "repository": { 46 | "type": "git", 47 | "url": "git+https://github.com/vivek12345/react-polling-hook.git" 48 | }, 49 | "bugs": { 50 | "url": "https://github.com/vivek12345/react-polling-hook/issues" 51 | }, 52 | "homepage": "https://github.com/vivek12345/react-polling-hook#readme", 53 | "jest": { 54 | "collectCoverageFrom": [ 55 | "src/**/*.{js,jsx,mjs}" 56 | ], 57 | "setupFiles": [ 58 | "/setupTests.js" 59 | ], 60 | "testMatch": [ 61 | "/src/**/__tests__/**/*.{js,jsx,mjs}", 62 | "/src/**/?(*.)(spec|test).{js,jsx,mjs}" 63 | ], 64 | "testEnvironment": "jsdom", 65 | "testURL": "http://localhost", 66 | "transform": { 67 | "^.+\\.(js|jsx|mjs)$": "/node_modules/babel-jest" 68 | }, 69 | "transformIgnorePatterns": [ 70 | "[/\\\\]node_modules[/\\\\].+\\.(js|jsx|mjs)$" 71 | ], 72 | "moduleFileExtensions": [ 73 | "web.js", 74 | "js", 75 | "json", 76 | "web.jsx", 77 | "jsx", 78 | "node", 79 | "mjs" 80 | ] 81 | }, 82 | "devDependencies": { 83 | "@babel/cli": "^7.0.0", 84 | "@babel/core": "^7.0.0", 85 | "@babel/plugin-proposal-class-properties": "^7.0.0", 86 | "@babel/plugin-transform-modules-commonjs": "^7.0.0", 87 | "@babel/plugin-transform-object-assign": "^7.0.0", 88 | "@babel/plugin-transform-spread": "^7.0.0", 89 | "@babel/preset-env": "^7.0.0", 90 | "@babel/preset-react": "^7.0.0", 91 | "all-contributors-cli": "^5.4.1", 92 | "babel-core": "7.0.0-bridge.0", 93 | "babel-eslint": "^9.0.0", 94 | "babel-jest": "^23.4.2", 95 | "babel-loader": "^8.0.0", 96 | "coveralls": "^3.0.2", 97 | "cross-env": "^5.2.0", 98 | "enzyme": "^3.5.0", 99 | "enzyme-adapter-react-16": "^1.3.0", 100 | "enzyme-to-json": "^3.3.4", 101 | "eslint": "^5.4.0", 102 | "eslint-config-react-app": "^2.1.0", 103 | "eslint-plugin-flowtype": "^2.50.0", 104 | "eslint-plugin-import": "^2.14.0", 105 | "eslint-plugin-jsx-a11y": "^6.1.1", 106 | "eslint-plugin-react": "^7.11.1", 107 | "jest": "^23.5.0", 108 | "jest-cli": "^23.5.0", 109 | "prettier": "^1.14.2", 110 | "prop-types": "^15.6.0", 111 | "raf": "^3.4.0", 112 | "react": "16.7.0-alpha.0 - next", 113 | "react-dom": "16.7.0-alpha.0 - next", 114 | "react-test-renderer": "^16.4.2", 115 | "regenerator-runtime": "^0.12.1", 116 | "webpack": "^4.17.1", 117 | "webpack-cli": "^3.1.0", 118 | "webpack-dev-server": "^3.1.7" 119 | }, 120 | "peerDependencies": { 121 | "prop-types": "^15.6.0", 122 | "react": "16.7.0-alpha.0 - next", 123 | "react-dom": "16.7.0-alpha.0 - next" 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /polyfills.js: -------------------------------------------------------------------------------- 1 | // In tests, polyfill requestAnimationFrame since jsdom doesn't provide it yet. 2 | // We don't polyfill it in the browser--this is user's responsibility. 3 | if (process.env.NODE_ENV === 'test') { 4 | require('raf').polyfill(global); 5 | } 6 | -------------------------------------------------------------------------------- /setupTests.js: -------------------------------------------------------------------------------- 1 | import { configure } from 'enzyme'; 2 | import Adapter from 'enzyme-adapter-react-16'; 3 | 4 | configure({ adapter: new Adapter() }); 5 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import usePolling from './usePolling'; 2 | export { usePolling }; 3 | -------------------------------------------------------------------------------- /src/usePolling.js: -------------------------------------------------------------------------------- 1 | import React, { useState, useEffect, useRef } from 'react'; 2 | 3 | const usePolling = config => { 4 | const version = React.version.split('-'); 5 | if (version[0] < '16.7.0') { 6 | throw new Error('Hooks are only supported in React 16.7.0-alpha release or above'); 7 | } 8 | let { url, interval = 3000, retryCount = 0, onSuccess, onFailure = () => {}, ...api } = config; 9 | const [isPolling, togglePolling] = useState(false); 10 | 11 | const persistedIsPolling = useRef(); 12 | const isMounted = useRef(); 13 | const poll = useRef(); 14 | 15 | persistedIsPolling.current = isPolling; 16 | 17 | useEffect(() => { 18 | isMounted.current = true; 19 | startPolling(); 20 | return () => { 21 | isMounted.current = false; 22 | stopPolling(); 23 | }; 24 | }, []); 25 | 26 | // if no url specified, throw an error 27 | if (!url) { 28 | throw new Error('No url provided to poll. Please provide a config object with the url param set'); 29 | } 30 | 31 | const shouldRetry = retryCount ? true : false; 32 | 33 | const stopPolling = () => { 34 | if (isMounted.current) { 35 | if (poll.current) { 36 | clearTimeout(poll.current); 37 | poll.current = null; 38 | } 39 | togglePolling(false); 40 | } 41 | }; 42 | 43 | const startPolling = () => { 44 | // why this does not update state? 45 | togglePolling(true); 46 | // call runPolling, which will start timer and call our api 47 | runPolling(); 48 | }; 49 | 50 | const runPolling = () => { 51 | const timeoutId = setTimeout(() => { 52 | /* onSuccess would be handled by the user of service which would either return true or false 53 | * true - This means we need to continue polling 54 | * false - This means we need to stop polling 55 | */ 56 | fetch(url, api) 57 | .then(resp => { 58 | return resp.json().then(data => { 59 | if (resp.ok) { 60 | return data; 61 | } else { 62 | return Promise.reject({ status: resp.status, data }); 63 | } 64 | }); 65 | }) 66 | .then(onSuccess) 67 | .then(continuePolling => { 68 | persistedIsPolling.current && continuePolling ? runPolling() : stopPolling(); 69 | }) 70 | .catch(error => { 71 | if (shouldRetry && retryCount > 0) { 72 | onFailure && onFailure(error); 73 | retryCount--; 74 | runPolling(); 75 | } else { 76 | onFailure && onFailure(error); 77 | stopPolling(); 78 | } 79 | }); 80 | }, interval); 81 | poll.current = timeoutId; 82 | }; 83 | 84 | return [isPolling, startPolling, stopPolling]; 85 | }; 86 | 87 | export default usePolling; 88 | -------------------------------------------------------------------------------- /src/usePolling.test.js: -------------------------------------------------------------------------------- 1 | describe('usePolling', () => { 2 | test('still pending', () => { 3 | expect(true).toBeTruthy(); 4 | }); 5 | }); 6 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | const webpack = require('webpack'); 3 | 4 | module.exports = { 5 | mode: process.env.NODE_ENV || 'production', 6 | devtool: 'source-map', 7 | entry: './src/index.js', 8 | output: { 9 | path: __dirname + '/dist', 10 | filename: 'ReactPollingHook.js', 11 | libraryTarget: 'umd', 12 | library: 'ReactPollingHook' 13 | }, 14 | module: { 15 | rules: [ 16 | { 17 | test: /\.js$/, 18 | exclude: /node_modules/, 19 | loader: 'babel-loader' 20 | } 21 | ] 22 | }, 23 | externals: ['react', 'react-dom', 'prop-types'], 24 | plugins: [ 25 | new webpack.DefinePlugin({ 26 | 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV) 27 | }) 28 | ] 29 | }; 30 | --------------------------------------------------------------------------------