{"id":13450485,"url":"https://github.com/moxystudio/react-promiseful","last_synced_at":"2025-03-23T16:31:31.262Z","repository":{"id":57342784,"uuid":"184162381","full_name":"moxystudio/react-promiseful","owner":"moxystudio","description":"A React component and hook to render children conditionally based on a promise state","archived":false,"fork":false,"pushed_at":"2020-03-15T12:19:19.000Z","size":1376,"stargazers_count":9,"open_issues_count":1,"forks_count":1,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-04-14T22:12:43.479Z","etag":null,"topics":["delay","promise","react","state","status","timeout"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/moxystudio.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-04-30T00:15:45.000Z","updated_at":"2021-05-10T21:38:37.000Z","dependencies_parsed_at":"2022-09-16T02:50:33.710Z","dependency_job_id":null,"html_url":"https://github.com/moxystudio/react-promiseful","commit_stats":null,"previous_names":["moxystudio/react-promise-status"],"tags_count":2,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moxystudio%2Freact-promiseful","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moxystudio%2Freact-promiseful/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moxystudio%2Freact-promiseful/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/moxystudio%2Freact-promiseful/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/moxystudio","download_url":"https://codeload.github.com/moxystudio/react-promiseful/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":221856412,"owners_count":16892438,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["delay","promise","react","state","status","timeout"],"created_at":"2024-07-31T07:00:35.103Z","updated_at":"2024-10-28T16:31:19.154Z","avatar_url":"https://github.com/moxystudio.png","language":"JavaScript","funding_links":[],"categories":["Packages"],"sub_categories":[],"readme":"# react-promiseful\n\n[![NPM version][npm-image]][npm-url] [![Downloads][downloads-image]][npm-url] [![Build Status][travis-image]][travis-url] [![Coverage Status][codecov-image]][codecov-url] [![Dependency status][david-dm-image]][david-dm-url] [![Dev Dependency status][david-dm-dev-image]][david-dm-dev-url]\n\n[npm-url]:https://npmjs.org/package/react-promiseful\n[downloads-image]:https://img.shields.io/npm/dm/react-promiseful.svg\n[npm-image]:https://img.shields.io/npm/v/react-promiseful.svg\n[travis-url]:https://travis-ci.org/moxystudio/react-promiseful\n[travis-image]:https://img.shields.io/travis/moxystudio/react-promiseful/master.svg\n[codecov-url]:https://codecov.io/gh/moxystudio/react-promiseful\n[codecov-image]:https://img.shields.io/codecov/c/github/moxystudio/react-promiseful/master.svg\n[david-dm-url]:https://david-dm.org/moxystudio/react-promiseful\n[david-dm-image]:https://img.shields.io/david/moxystudio/react-promiseful.svg\n[david-dm-dev-url]:https://david-dm.org/moxystudio/react-promiseful?type=dev\n[david-dm-dev-image]:https://img.shields.io/david/dev/moxystudio/react-promiseful.svg\n\nA React component and hook to render children conditionally based on a promise status.\n\n\n## Installation\n\n```sh\n$ npm install react-promiseful\n```\n\nThis library is written in modern JavaScript and is published in both CommonJS and ES module transpiled variants. If you target older browsers please make sure to transpile accordingly.\n\n\n## Demo\n\nYou may see a simple demo of `react-promiseful` in [https://moxystudio.github.io/react-promiseful](https://moxystudio.github.io/react-promiseful/).\n\n\n## Usage\n\n**With `\u003cPromiseState\u003e` component**:\n\n```js\nimport React, { useMemo, useState } from 'react';\nimport { PromiseState } from 'react-promiseful';\n\nconst SomeComponent = (props) =\u003e {\n    const [savePromise, setSavePromise] = useState();\n    const handleSave = useMemo(\n        () =\u003e () =\u003e setSavePromise(props.save()),\n        [props.save]\n    );\n\n    return (\n        \u003cdiv\u003e\n            \u003cbutton disabled={ saveState.status === 'pending' } onSave={ handleSave }\u003e\n                Save\n            \u003c/button\u003e\n\n            \u003cPromiseState promise={ savePromise }\u003e\n                { (saveState) =\u003e (\n                    \u003cp\u003e\n                        { saveState.status === 'pending' \u0026\u0026 'Saving...' }\n                        { saveState.status === 'fulfilled' \u0026\u0026 'Saved!' }\n                        { saveState.status === 'rejected' \u0026\u0026 'Oops, failed to save' }\n                    \u003c/p\u003e\n                ) }\n            \u003c/PromiseState\u003e\n        \u003c/div\u003e\n    );\n}\n```\n\n**With `usePromiseState()` hook**:\n\n```js\nimport React, { useMemo, useState } from 'react';\nimport { usePromiseState } from 'react-promiseful';\n\nconst SomeComponent = (props) =\u003e {\n    const [savePromise, setSavePromise] = useState();\n    const saveState = usePromiseState(savePromise);\n    const handleSave = useMemo(\n        () =\u003e () =\u003e setSavePromise(props.save()),\n        [props.save]\n    );\n\n    return (\n        \u003cdiv\u003e\n             \u003cbutton disabled={ saveState.status === 'pending' } onSave={ handleSave }\u003e\n                Save\n            \u003c/button\u003e\n\n            \u003cp\u003e\n                { saveState.status === 'pending' \u0026\u0026 'Saving..' }\n                { saveState.status === 'fulfilled' \u0026\u0026 'Saved!' }\n                { saveState.status === 'rejected' \u0026\u0026 'Oops, failed to save' }\n            \u003c/p\u003e\n        \u003c/div\u003e\n    );\n}\n```\n\n## API\n\n- [`\u003cPromiseState\u003e`](#promisestate)\n- [`usePromiseState(promise, [options])`](#usepromisestatepromise-options)\n- [`getPromiseState(promise)`](#getpromisestatepromise)\n\n### PromiseState\n\nThe `\u003cPromiseState\u003e` component allows you to conditionally render children based on the promise status and fulfillment/rejection value. It leverages the [render props](https://reactjs.org/docs/render-props.html) technique to know what to render.\n\n#### Props\n\n##### promise\n\nType: `Promise`\n\nThe promise to observe.\n\n##### children\n\nA render prop function with the following signature:\n\n```js\n(state) =\u003e {}\n```\n\nThe `state` argument is an object that contains the following properties:\n\n- `status` is one of `none` (when there's no promise), `pending`, `rejected`, `fulfilled`\n- `value` is either the fulfillment value or the rejection value\n- `withinThreshold` indicating if we are still within the configured [`thresholdMs`](#thresholdms)\n\n##### thresholdMs\n\nType: `number`   \nDefault: 0\n\nThe timespan in ms to consider the promise within the threshold. Useful if you want to render a loading only when the promise is taking some time.\n\nThe state will contain a `withinThreshold` boolean property for you to use in the `children` render prop. Moreover, you may also use \"withinThreshold\" variants in the [statusMap](#statusmap) and [onSettleDelay](#onsettledelay) props.\n\n##### statusMap\n\nType: `Object`\n\nAn object to map statuses, useful when you want to use other names:\n\n```js\n{\n    pending: 'loading',\n    fulfilled: 'success',\n    rejected: 'error',\n}\n```\n\nWhen the [`thresholdMs`](#thresholdms) prop is used, you are also able to map the \"withinThreshold\" variants. This is useful if you want to hide visual feedback that is too quick. For instance, to avoid having any spinners and success feedback within the threshold:\n\n```js\n{\n    pendingWithinThreshold: 'none',\n    fulfilledWithinThreshold: 'none',\n    pending: 'loading',\n    fulfilled: 'success',\n    rejected: 'error',\n}\n```\n\nYou may omit statuses you don't want to map and the default ones will be used. Moreover, if no \"withinThreshold\" statuses are defined, their normal counterparts will be used.\n\n### onSettle\n\nType: `Function`\n\nA callback to be called whenever the promise fulfills or rejects. It receives the `state` as argument:\n\n```js\n(state) =\u003e {}\n```\n\nThis is useful to trigger a change in a user-interface after the promise resolves:\n\n```js\nconst handleSettle = ({ status }) =\u003e {\n    if (status === 'fulfilled') {\n        complete(); // Imaginary function that completes the operation in the UI\n    }\n};\n```\n\n### onSettleDelayMs\n\nType: `number`, `Object`   \nDefault: 0\n\nThe delay before calling `onSettle`. This is useful if you have success animations that must complete before triggering a change in the user-interface.\n\nYou may either specify a number to signal the same delay for both `fulfilled` and `rejected` statuses or an object containing the granular delays:\n\n```js\n{\n    fulfilled: 2000,\n    rejected: 2000,\n}\n```\n\nWhen the [`thresholdMs`](#thresholdms) prop is used, you are also able to also map the \"withinThreshold\" variants. For instance, you may want the callback to be called with a delay, except when there is no visual-feedback:\n\n```js\n{\n    fulfilledWithinThreshold: 0,\n    fulfilled: 2000,\n    rejected: 2000,\n}\n```\n\nYou may omit delays you don't want to map and the default ones will be used. Moreover, if no \"withinThreshold\" statuses are defined, their normal counterparts will be used.\n\n### usePromiseState(promise, [options])\n\nThe hook version of the `\u003cPromiseState\u003e` component. The `options` available to both are exactly the same.\n\n```js\nconst promiseState = usePromiseState(somePromise);\n```\n\nThe returned value from the hook is the promise state, an object that contains the following properties:\n\n- `status` is one of `none` (when there's no promise), `pending`, `rejected`, `fulfilled`\n- `value` is either the fulfillment value or the rejection value\n- `withinThreshold` indicating if we are still within the configured [`thresholdMs`](#thresholdms)\n\n### getPromiseState(promise)\n\nReturns the current promise state, an object with `status` and `value`.\n\nIf the `promise` was yet not used in `\u003cPromiseState\u003e` or `usePromiseState()`, the promise state will be `pending`.\n\n\n## Tests\n\n```sh\n$ npm test\n$ npm test -- --watch # during development\n```\n\n\n## License\n\nReleased under the [MIT License](https://www.opensource.org/licenses/mit-license.php).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoxystudio%2Freact-promiseful","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmoxystudio%2Freact-promiseful","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmoxystudio%2Freact-promiseful/lists"}