{"id":18989159,"url":"https://github.com/godaddy/reduxful","last_synced_at":"2025-04-22T11:05:53.132Z","repository":{"id":32956310,"uuid":"147703541","full_name":"godaddy/reduxful","owner":"godaddy","description":"Manage request data in Redux state by generating actions, reducers, and selectors automatically.","archived":false,"fork":false,"pushed_at":"2023-11-06T17:00:39.000Z","size":799,"stargazers_count":27,"open_issues_count":8,"forks_count":13,"subscribers_count":10,"default_branch":"master","last_synced_at":"2025-04-15T12:50:47.706Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"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/godaddy.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":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2018-09-06T16:39:53.000Z","updated_at":"2023-05-11T13:29:59.000Z","dependencies_parsed_at":"2024-06-21T16:33:01.027Z","dependency_job_id":"e7440867-f76d-49a8-bcf8-2d0b5827ea31","html_url":"https://github.com/godaddy/reduxful","commit_stats":null,"previous_names":[],"tags_count":19,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Freduxful","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Freduxful/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Freduxful/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/godaddy%2Freduxful/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/godaddy","download_url":"https://codeload.github.com/godaddy/reduxful/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":250227238,"owners_count":21395727,"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":[],"created_at":"2024-11-08T17:05:29.550Z","updated_at":"2025-04-22T11:05:53.039Z","avatar_url":"https://github.com/godaddy.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Reduxful\n\n[![Version npm](https://img.shields.io/npm/v/reduxful.svg?style=flat-square)](https://www.npmjs.com/package/reduxful)\n[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/godaddy/reduxful/CI?style=flat-square)](https://github.com/godaddy/reduxful/actions/workflows/ci.yml)\n[![Coverage Status](https://img.shields.io/coveralls/godaddy/reduxful/master.svg?style=flat-square)](https://coveralls.io/r/godaddy/reduxful?branch=master)\n\nClient-side state is often related to data requested from RESTful web services.\nReduxful aims to reduce the boilerplate for managing requested data in Redux \nstate by generating **actions**, **reducers**, and **selectors** for you.\n\n## Installation\n\nInstall `reduxful` along with `redux-thunk` middleware.\n\n```bash\nyarn add reduxful redux-thunk\n```\nor \n```bash\nnpm install --save reduxful redux-thunk\n```\n\n## Documentation \n\n- [API Docs]\n- [Advanced setups]\n- [Advanced actionCreators]\n- React\n  - [React Addons Docs]\n  - [React Examples]\n\n## Usage\n\n### Describe an API\n\n```js\n// doodad-api.js\n\nconst apiDesc = {\n  getDoodad: {\n    url: 'http://api.my-service.com/doodads/:id'\n  },\n  getDoodadList: {\n    url: 'http://api.my-service.com/doodads'\n  }\n};\n```\n\nIn its purest form, an [API description] is an object of keys following the \n_verbNoun_ convention by which to name a resource. The values associated\nwith these are the [request description], which at a minimum requires an `url`.\n\nThese resource names are also the names generated for the `actionCreators`\nand `selectors`.\n\n### Make a Request Adapter\n\nBefore we can call our endpoints, we need to set up a [Request Adapter] to use\nour AJAX or Fetch library of choice. A [convenience function][makeFetchAdapter]\nis available to make an adapter for the [Fetch API]. \n\n```js\n// my-request-adapter.js\n\nimport fetch from 'cross-fetch';\nimport { makeFetchAdapter } from 'reduxful';\n\nexport default makeFetchAdapter(fetch);\n```\n\nIn this example, we are using [cross-fetch] which allows universal fetching\non both server and browser. Any other library can be used, as long as\nan adapter is implemented for adjusting params and returning the expected\nPromise.\n\n### Setup Reduxful Instance\n\nTo generate Redux tooling around an API Description, pass it along with the \nname you want your Redux state property to be. Also, include the request adapter\nin the [api config] argument.\n\n```js\n// doodad-api.js\n\nimport Reduxful from 'reduxful';\nimport requestAdapter from './my-request-adapter';\n\nconst apiConfig = { requestAdapter };\nconst doodadApi = new Reduxful('doodadApi', apiDesc, apiConfig);\n\nexport default doodadApi;\n```\n\nThe variable that you assign the Reduxful instance to has the\n`actions`, `reducers`, and `selectors` need for working with Redux.\n\n### Attach to Store\n\nThe first thing to using the Reduxful instance with Redux is to attach your\nreducers to a Redux store.\n\n```js\n// store.js\n\nimport { createStore, combineReducers, applyMiddleware } from 'redux';\nimport thunk from 'redux-thunk';\nimport doodadApi from './doodad-api';\n\nconst rootReducer = combineReducers(doodadApi.reducers);\nconst store = createStore(\n  rootReducer,\n  applyMiddleware(thunk)\n);\n\nexport default store;\n```\n\nReduxful depends on the `redux-thunk` middleware and uses it for the \nactionCreators.\n\n### Dispatch Actions\n\nThe Reduxful instance has an `actionCreators` property (or _`actions`_ as an\nalias) from which you can dispatch action with the Redux store.\n\n```js\nimport doodadApi from './doodad-api';\nimport store from './store';\n\nstore.dispatch(doodadApi.actionCreators.getDoodadList());\n\nstore.dispatch(doodadApi.actionCreators.getDoodad({ id: '123' }));\n```\n\nOur list resource description does not require any path or query params.\nHowever, our single resource does require an id as a path param, so we this\nin the params object as the first argument to the `actionCreator`.\n\n### Select from State\n\nThe Reduxful instance has a `selectors` property by which you can easily \nselect resources from the Redux state.\n\n```js\nimport doodadApi from './doodad-api';\nimport store from './store';\n\nconst doodadList = doodadApi.selectors.getDoodadList(store.getState());\n\nconst doodad = doodadApi.selectors.getDoodad(store.getState(), { id: '123' });\n```\n\nTo select the list resource, we only need to pass the store's state. For our\nsingle resource, we also pass the same params used in the `actionCreator`. \nParams are used to key a resource in the redux state, which allows \nmultiple requests to the same endpoint with different details to be managed. \n\n### Resources\n\n[Resources] are the objects selected from Redux state and which track a\nrequest and resulting data from its response, with properties indicating\nstatus: `isUpdating`, `isLoaded`, and `hasError`.\n\n```js\nimport doodadApi from './doodad-api';\nimport store from './store';\n\nfunction outputResultsExample(resource) {\n  if (!resource) {\n    return 'No resource found.';\n  } else if (resource.isUpdating \u0026\u0026 !(resource.isLoaded || resource.hasError)) {\n    return 'Loading...';\n  } else if (resource.isLoaded) {\n    return resource.value;\n  } else if (resource.hasError) {\n    return resource.error;\n  }\n}\n\nconst doodadList = doodadApi.selectors.getDoodadList(store.getState());\n\noutputResultsExample(doodadList);\n```\n\nIn this example, except for the first request, we always return the value\nor error data even if an update is occurring. When a first request is made,\nor for any subsequent requests, `isUpdating` will be true. After a response,\nthe resource will have either `isLoaded` or `hasError` set to true.\n\nIf an action has not been dispatch, there will be no resource selected from\nstate. In the situation, the utility functions [isUpdating], [isLoaded], and\n[hasError] can be used for checking status safely against an undefined resource.\n\n### From here\n\nContinue learning about Reduxful's more [advanced setups].\n\n\n\u003c!-- Links --\u003e\n[API Docs]:docs/api.md\n[React Addons Docs]:docs/react-addons-api.md\n[React Examples]:docs/react-examples.md\n[Advanced setups]:docs/advanced-setups.md\n[Advanced actionCreators]:docs/advanced-action-creators.md\n\n[API Description]:docs/api.md#ApiDescription\n[API Config]:docs/api.md#ApiDescription\n[Request Description]:docs/api.md#RequestDescription\n[Request Adapter]:docs/api.md#RequestAdapter\n[makeFetchAdapter]:docs/api.md#makeFetchAdapter\n[Resource]:docs/api.md#Resource\n[Resources]:docs/api.md#Resource\n[isLoaded]:docs/api.md#isLoaded\n[isUpdating]:docs/api.md#isUpdating\n[hasError]:docs/api.md#hasError\n\n\n\u003c!-- External Links --\u003e\n[cross-fetch]:https://github.com/lquixada/cross-fetch#cross-fetch\n[redux-thunk]:https://github.com/reduxjs/redux-thunk#redux-thunk\n[Fetch API]:https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgodaddy%2Freduxful","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgodaddy%2Freduxful","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgodaddy%2Freduxful/lists"}