{"id":13486260,"url":"https://github.com/kouhin/redux-dataloader","last_synced_at":"2025-08-21T17:32:00.510Z","repository":{"id":57350514,"uuid":"51807031","full_name":"kouhin/redux-dataloader","owner":"kouhin","description":"Loads async data for Redux apps focusing on preventing duplicated requests and dealing with async dependencies.","archived":false,"fork":false,"pushed_at":"2017-11-14T03:56:23.000Z","size":111,"stargazers_count":138,"open_issues_count":1,"forks_count":5,"subscribers_count":2,"default_branch":"develop","last_synced_at":"2024-12-09T04:10:53.454Z","etag":null,"topics":["action","async","duplicates","react","redux","thunk"],"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/kouhin.png","metadata":{"files":{"readme":"README.md","changelog":null,"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":"2016-02-16T04:07:16.000Z","updated_at":"2024-09-23T10:35:23.000Z","dependencies_parsed_at":"2022-08-28T19:00:27.307Z","dependency_job_id":null,"html_url":"https://github.com/kouhin/redux-dataloader","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kouhin%2Fredux-dataloader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kouhin%2Fredux-dataloader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kouhin%2Fredux-dataloader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kouhin%2Fredux-dataloader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kouhin","download_url":"https://codeload.github.com/kouhin/redux-dataloader/tar.gz/refs/heads/develop","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":230523761,"owners_count":18239445,"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":["action","async","duplicates","react","redux","thunk"],"created_at":"2024-07-31T18:00:42.697Z","updated_at":"2024-12-20T02:06:49.111Z","avatar_url":"https://github.com/kouhin.png","language":"JavaScript","funding_links":[],"categories":["Redux Helpers"],"sub_categories":[],"readme":"# Redux Data Loader\n\n[![CircleCI](https://circleci.com/gh/kouhin/redux-dataloader.svg?style=svg)](https://circleci.com/gh/kouhin/redux-dataloader)\n[![npm](https://img.shields.io/npm/v/redux-dataloader.svg)](https://npmjs.org/package/redux-dataloader)\n\nLoads async data for Redux apps focusing on preventing duplicated requests and dealing with async dependencies.\n\nDeeply inspired by [alt Data Souces API](http://alt.js.org/docs/async), also inspired by [redux-saga](https://github.com/yelouafi/redux-saga).\n\nInstead of using redux-thunk, it handles wrapped actions and sideload async data.\nIt also caches data requests for a while in order to prevent duplicated requests.\n\n## Installation\n\n```\nnpm install redux-dataloader --save\n```\n\n## Usage\n\n### 1. Define actions and update the request action with load()\n\n#### `userActions.js`\n```javascript\nimport { load } from 'redux-dataloader';\n\nexport const FETCH_USER_REQUEST = 'myapp/user/FETCH_USER/REQUEST';\nexport const FETCH_USER_SUCCESS = 'myapp/user/FETCH_USER/SUCCESS';\nexport const FETCH_USER_FAILURE = 'myapp/user/FETCH_USER/FAILURE';\n\nexport function fetchUserRequest(username) {\n  // use `load` to wrap a request action, load() returns a Promise\n  return load({\n    type: FETCH_USER_REQUEST,\n    payload: {\n      username: username,\n    },\n  })\n}\n\nexport function fetchUserSuccess(username, data) {\n  // ...\n}\n\nexport function fetchUserFailure(username, error) {\n  // ...\n}\n\n```\n\n### 2. Create a data loader\n\n#### `dataloaders.js`\n\n```javascript\nimport { createLoader, fixedWait } from 'redux-dataloader';\n\nimport * as userActions from './userActions';\n\nconst userLoader = createLoader(userActions.FETCH_USER_REQUEST, {\n  /*\n   * (required) Handle fetched data, return a success action\n   */\n  success: (context, result) =\u003e {\n    // you can get original request action from context\n    const action = context.action;\n    const username = action.payload.username;\n    return userActions.fetchUserSuccess(username, result);\n  },\n  /*\n   * (required) Handle error, return a failure action\n   */\n  error: (context, error) =\u003e {\n    const action = context.action;\n    const username = action.payload.username;\n    return userActions.fetchUserFailure(username, error);\n  },\n  /*\n   * (optional) By default, original request action will be dispatched. But you can still modify this process.\n   */\n  // loading: ({ action }) =\u003e {}\n  /*\n   * (required) Fetch data.\n   * We use yahoo/fetchr as an example.\n   */\n  fetch: (context) =\u003e {\n    const action = context.action;\n    const username = action.payload.username;\n\n    const fetchr = context.fetchr;\n    return fetchr.read('userService')\n      .params({\n        username,\n      }).end();\n  },\n  /*\n   * (optional) !!! Different from alt API.\n   * When shouldFetch returns false, it will prevent fetching data.\n   */\n  shouldFetch: (context) =\u003e {\n    const action = context.action;\n    const username = action.payload.username;\n    const getState = context.getState;\n    return !getState().user.users[username];\n  }\n}, {\n  ttl: 10000,\n  retryTimes: 3,\n  retryWait: fixedWait(500),\n});\n\nexport default [userLoader];\n```\n\n### 3. Register middleware\n\n#### `configureStore.js`\n\n```javascript\nimport { createStore, applyMiddleware } from 'redux';\nimport { createDataLoaderMiddleware } from `redux-dataloader`;\nimport { Fetchr } from 'fetchr';\nimport reducer from './reducers';\nimport loaders from './dataloaders';\n\nconst fetcher = new Fetcher({\n  xhrPath: '/api',\n});\n\n// create middleware, you can add extra arguments to data loader context\nconst dataLoaderMiddleware = createDataLoaderMiddleware(loaders, { fetchr });\n\nconst store = createStore(\n  reducer,\n  applyMiddleware(dataLoaderMiddleware)\n)\n\n// ...\n```\n\n### 4. Use it for your application\n\nThen, just use it in your application.\nThe following is an example that combined with [redial](https://github.com/markdalgleish/redial) for isomorphic use.\n\n```javascript\nimport { provideHooks } from 'redial';\nimport { fetchUserRequest } from 'userActions';\nimport { fetchArticleRequest } from 'articleAction';\nimport { fetchArticleSkinRequest } from 'articleSkinAction';\n\n// the router location is: /:username/:articleId\n// Data dependency: user \u003c= article \u003c= articleSkin\nasync function fetchData({param, dispatch, getState}) {\n  try {\n    // 1. Fetch user\n    const username = params.username;\n    await dispatch(fetchUserRequest(username)); // wait for response\n\n    // 2. Fetch article by userId and articleId, you may use useId for authentication\n    const user = getState().user.users[username];\n    if (!user) {\n      throw new Error(`user_not_found: ${username}`);\n    }\n    const articleId = params.articleId;\n    await dispatch(fetchArticleRequest(user.id, articleId));\n\n    // 3. Fetch article skin by articleId\n    const article = getState().article.articles[articleId];\n    if (!article) {\n      throw new Error(`article_not_found: ${articleId}`);\n    }\n    await dispatch(fetchArticleSkinRequest(article.skinId));\n  } catch (err) {\n    // ...\n  }\n}\n\nfunction mapStateToProps(state, owndProps) {\n  // ...\n}\n\n@connect(mapStateToProps)\n@provideHooks({\n  fetch: fetchData,\n})\nexport default class ArticleContainer extends React.Component {\n  // ...\n}\n```\n\nYou can also write `fetchData()` with Promise:\n\n```javascript\nfunction fetchData({param, dispatch, getState}) {\n  return Promise.resolve().then(() =\u003e {\n    // 1. Fetch user\n    const username = params.username;\n    return dispatch(fetchUserRequest(username));\n  }).then(() =\u003e {\n    // 2. Fetch article by userId and articleId, you may use useId for authentication\n    const user = getState().user.users[username];\n    if (!user) {\n      throw new Error(`user_not_found: ${username}`);\n    }\n    const articleId = params.articleId;\n    return dispatch(fetchArticleRequest(user.id, articleId));\n  }).then(() =\u003e {\n    // 3. Fetch article skin by articleId\n    const article = getState().article.articles[articleId];\n    if (!article) {\n      throw new Error(`article_not_found: ${articleId}`);\n    }\n    return dispatch(fetchArticleSkinRequest(article.skinId));\n  }).catch((err) =\u003e {\n    // error handler\n    // ...\n  })\n}\n```\n\n## Documentation\n\n- [API](/API.md)\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkouhin%2Fredux-dataloader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkouhin%2Fredux-dataloader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkouhin%2Fredux-dataloader/lists"}