{"id":22106977,"url":"https://github.com/legitcode/redux-save","last_synced_at":"2025-08-02T15:04:56.339Z","repository":{"id":57351305,"uuid":"45638779","full_name":"Legitcode/redux-save","owner":"Legitcode","description":"Full featured middleware for handling async actions and automagically saving data (For RN \u0026 Web)","archived":false,"fork":false,"pushed_at":"2015-12-04T14:16:25.000Z","size":9,"stargazers_count":32,"open_issues_count":0,"forks_count":0,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-07-25T07:16:04.633Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/Legitcode.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-11-05T20:55:48.000Z","updated_at":"2019-07-15T16:32:09.000Z","dependencies_parsed_at":"2022-08-31T03:50:28.668Z","dependency_job_id":null,"html_url":"https://github.com/Legitcode/redux-save","commit_stats":null,"previous_names":["legitcode/redux-react-fetch"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/Legitcode/redux-save","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Legitcode%2Fredux-save","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Legitcode%2Fredux-save/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Legitcode%2Fredux-save/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Legitcode%2Fredux-save/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/Legitcode","download_url":"https://codeload.github.com/Legitcode/redux-save/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/Legitcode%2Fredux-save/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268408189,"owners_count":24245576,"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","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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-12-01T08:13:23.820Z","updated_at":"2025-08-02T15:04:56.309Z","avatar_url":"https://github.com/Legitcode.png","language":"JavaScript","readme":"\n#redux-save\n\n##Stores\n\nWork the same as regular redux, except when you create your store, do it like this:\n\n```js\nimport initialState from 'redux-save/web'\n\nconst store = createStore(counterApp, initialState('counterApp'))\n```\n\nPass in a unique name for each store, and `redux-save` does the rest.\nOn the server, you should pass down data to `window.__INITIAL_STATE__` if you're using this on the web.\n\nWant to use immutablejs? That's what functions are for:\n\n```js\nconst store = createStore(counterApp, Immutable.Map(initialState('counterApp')))\n```\n\n\n\n\n\n##Actions\n\n`npm install redux-react-fetch --save`\n\n![](http://f.cl.ly/items/2V1Y3R0b3F0v0t2E1x0H/gif.gif)\n\n###What is this?\n\nIt's not as complicated as it sounds. There's a bunch of promise-based middleware out there, this one simple expands on that idea. Take a look at [redux-fetch](https://www.npmjs.com/package/redux-fetch). This library is, in my opinion, easier to use and does something awesome, and that's merging. Before we get to that, here's the idea:\n\n1. Write an action for an ajax request\n2. dispatch an optimistic update, with styling merged in!\n3. dispatch on success or fail, with new styling\n\n###What's merging? Why Styles?\n\nIf you are writing a lot of promises, chances are you have been checking if requests finish, and adding in some sort of logic to show the user something is wrong. This middleware aims to make doing this a lot easier. I'm hoping more people have ideas on making this even better. My main use case for this is merging in styles and doing css transitions in between state changes.\n\n##Example\n\n###Include the Middleware\n\nYou can pass in your preferred fetch implementation!\n\n~~~js\nimport { createStore, applyMiddleware } from 'redux'\nimport reduxReactFetch from 'redux-react-fetch'\nimport fetch from 'isomorphic-fetch'\n\nconst createWithMiddleware = applyMiddleware(\n  reduxReactFetch(fetch)\n)(createStore)\n~~~\n\n###Write an action\n\n~~~js\nexport function updateTicket(ticketId, type, value){\n  return {\n    type: 'updateArticle',\n    url: `http://test.com`,\n    body: {\n      article_id: ticketId,\n      title: 'New Title'\n    },\n    then: 'updateTicketFinished'\n  }\n}\n~~~\n\nThere's some things inferred here:\n\n- If no `options` are passed in the action, it will default to the following:\n\n~~~js\nconst options = {\n  credentials: 'same-origin',\n  method: 'post',\n  headers: {\n    'Accept': 'application/json',\n    'Content-Type': 'application/json'\n  }\n}\n~~~\n- It is a wrapper around [isomorphic-fetch](https://github.com/matthew-andrews/isomorphic-fetch). You can pass anything according to the fetch spec.\n- The body is JSON stringified for you, if it is a plain object. (If you send multipart/form-data you don't want it stringified)\n- `then` is optional. The same action will be called on success if it is not set. You can set `catch` as well.\n- `mergeTo` is the key to merge your object to, defaults to `body`\n\n###Merge all the things!\n\nNow it's the cool part. By default, a `style` object is merged into the `body` object in your action. When you set the state in your store, you don't need to do anything extra.\n\n~~~js\ncase 'updateArticle':\n  return state.update(action.body.article_id, () =\u003e {\n    return action.body\n  })\ncase 'updateTicketFinished':\nreturn state.update(action.body.article_id, () =\u003e {\n  return action.response.result\n})\n~~~\n\nStill don't get what's cool? Behind the scenes `style` (that you can change, you'll see) was added to the result and initial body:\n\n~~~js\nimport React from 'react'\n\nexport default ({title, style}) =\u003e (\n  \u003ch1 style={style}\u003e{title}\u003c/h1\u003e\n)\n~~~\nWhen you dispatch the action to update the title, it will fade to 0.5 opacity, on response it will fade back to 1. And you didn't have to do anything! Cool right? If you don't like the defaults, here's how to change it. Pass in some stuff to the middleware when you apply it:\n\n~~~js\nconst start = {\n  opacity: 0.5,\n  transition: 'opacity .5s ease-in-out'\n}\n\nconst end = {\n  opacity: 1,\n  transition: 'opacity .5s ease-in-out'\n}\n\nconst endFail = {\n  opacity: 1,\n  border: 'solid red 1px',\n  transition: 'opacity .5s ease-in-out'\n}\n\nconst createWithMiddleware = applyMiddleware(\n  reduxFetchMerger(fetch, {start, end, endfail})\n)(createStore)\n~~~\n\nI'm fairly new to redux, so there may be some things I can improve. I also didn't document everything, hopefully I will soon!\n\n##Example File Upload Action\n\n~~~js\nexport function newComment(comment, postId, attachments){\n  let body = new FormData()\n  attachments.forEach((file)=\u003e {\n    body.append('attachments[]', file)\n  })\n  body.append('user_id', user.id)\n  body.append('text', comment.text)\n  if(comment.status) body.append('status_id', comment.status)\n\n  return {\n    type: 'newComment',\n    url: `https://test.com`,\n    body,\n    comment,\n    postId,\n    mergeTo: 'comment',\n    options: {\n      credentials: 'same-origin',\n      method: 'post',\n    },\n    then: 'updateLatestComment'\n  }\n~~~\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flegitcode%2Fredux-save","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flegitcode%2Fredux-save","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flegitcode%2Fredux-save/lists"}