{"id":13518362,"url":"https://github.com/clarus/redux-ship","last_synced_at":"2025-04-04T10:08:34.561Z","repository":{"id":57351548,"uuid":"65606420","full_name":"clarus/redux-ship","owner":"clarus","description":"Side effects with snapshots for Redux.","archived":false,"fork":false,"pushed_at":"2022-01-20T10:06:20.000Z","size":1456,"stargazers_count":609,"open_issues_count":4,"forks_count":19,"subscribers_count":12,"default_branch":"master","last_synced_at":"2024-10-11T21:46:33.094Z","etag":null,"topics":["redux","redux-ship","snapshot"],"latest_commit_sha":null,"homepage":"https://clarus.github.io/redux-ship/","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/clarus.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-08-13T07:56:37.000Z","updated_at":"2024-05-23T00:43:14.000Z","dependencies_parsed_at":"2022-09-18T22:40:16.435Z","dependency_job_id":null,"html_url":"https://github.com/clarus/redux-ship","commit_stats":null,"previous_names":[],"tags_count":4,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clarus%2Fredux-ship","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clarus%2Fredux-ship/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clarus%2Fredux-ship/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/clarus%2Fredux-ship/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/clarus","download_url":"https://codeload.github.com/clarus/redux-ship/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247156248,"owners_count":20893196,"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":["redux","redux-ship","snapshot"],"created_at":"2024-08-01T05:01:43.986Z","updated_at":"2025-04-04T10:08:34.530Z","avatar_url":"https://github.com/clarus.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","目录","Utilities","Marks"],"sub_categories":["\u003ca id=\"state\"\u003e状态管理\u003c/a\u003e","Side Effects","[React - A JavaScript library for building user interfaces](http://facebook.github.io/react)"],"readme":"# ![Logo](https://raw.githubusercontent.com/clarus/icons/master/rocket-48.png) Redux Ship\n\u003e Side effects with snapshots for Redux.\n\n[![travis status](https://img.shields.io/travis/clarus/redux-ship/master.svg?label=travis-ci)](https://travis-ci.org/clarus/redux-ship)\n[![appveyor status](https://img.shields.io/appveyor/ci/clarus/redux-ship.svg?label=app-veyor)](https://ci.appveyor.com/project/clarus/redux-ship)\n[![npm version](https://img.shields.io/npm/v/redux-ship.svg)](https://www.npmjs.com/package/redux-ship)\n[![npm downloads](https://img.shields.io/npm/dm/redux-ship.svg)](https://www.npmjs.com/package/redux-ship)\n\nRedux Ship is a side effects handler for [Redux](https://github.com/reactjs/redux) with a built-in system of **snapshots** for:\n\n* **live debugging** thanks to a graphical visualization of the side effects;\n* simpler **unit tests** with snapshot testing.\n\nThe key insight is to use generators to serialize all the side effects, including the control flow of the code, using the approach of *free monads*. Additionally, we provide a **composition mechanism** of sub-stores with effects and **full typing** (for now only in [Flow](https://flow.org/)).\n\n## Install\n```\nnpm install --save redux-ship\n```\n\n## Documentation\n* [Demo](https://clarus.github.io/redux-ship-devtools/)\n* [Tutorial](https://clarus.github.io/redux-ship/docs/tutorial/)\n* [API Reference](https://clarus.github.io/redux-ship/docs/api.html)\n\n## Example\nGet the movies of R2D2 using the [StarWars API](https://swapi.co/):\n```js\n// Check if we already have the list of movies in the Redux store.\nconst currentMovies = yield* Ship.getState(state =\u003e state.movies);\nif (!currentMovies) {\n  // If not, notify Redux that we start loading the movies.\n  yield* Ship.commit({type: 'LoadStart'});\n  // Get the description of R2D2 with an API call.\n  const r2d2 = yield* Effect.httpRequest('https://swapi.co/api/people/3/');\n  // For each movie of R2D2:\n  const movies = yield* Ship.all(JSON.parse(r2d2).films.map(function* (movieUrl) {\n    // Get the movie title with an API call.\n    const movie = yield* Effect.httpRequest(movieUrl);\n    return JSON.parse(movie).title;\n  }));\n  // Write the list of movies in the Redux store.\n  yield* Ship.commit({type: 'LoadSuccess', movies});\n}\n```\n\nWith the [Redux Ship devtools](https://github.com/clarus/redux-ship-devtools) we see the following snapshot of the execution:\n![Snapshot](docs/snapshot.png)\n\nThis shows us that we:\n\n* access the Redux state;\n* dispatch the action `LoadStart`;\n* make an HTTP call;\n* make seven HTTP calls in parallel (to get the movie titles);\n* dispatch the action `LoadSuccess`.\n\nEven without reading the code we get a sense of what the application does. By clicking on each pill we see the details of each element, like:\n\n* an access to a value in the store:\n\n![snapshot-get-state](docs/snapshot-get-state.png)\n\n* a dispatch of an action to the store:\n\n![snapshot-load-success](docs/snapshot-load-success.png)\n\n* an other side effect (API call, cookies update, ...) with the effect and its result:\n\n![snapshot-http-request](docs/snapshot-http-request.png)\n\nWe also get a serialized snapshot, directly usable to make a unit test:\n```js\n[\n  {\n    \"type\": \"GetState\",\n    \"state\": null\n  },\n  {\n    \"type\": \"Commit\",\n    \"commit\": {\n      \"type\": \"LoadStart\"\n    }\n  },\n  {\n    \"type\": \"Effect\",\n    \"effect\": {\n      \"type\": \"HttpRequest\",\n      \"url\": \"https://swapi.co/api/people/3/\"\n    },\n    \"result\": \"{\\\"name\\\":\\\"R2-D2\\\",\\\"height\\\":\\\"96\\\",\\\"mass\\\":\\\"32\\\",\\\"hair_color\\\":\\\"n/a\\\",\\\"skin_color\\\":\\\"white, blue\\\",\\\"eye_color\\\":\\\"red\\\",\\\"birth_year\\\":\\\"33BBY\\\",\\\"gender\\\":\\\"n/a\\\",\\\"homeworld\\\":\\\"https://swapi.co/api/planets/8/\\\",\\\"films\\\":[\\\"https://swapi.co/api/films/2/\\\",\\\"https://swapi.co/api/films/5/\\\",\\\"https://swapi.co/api/films/4/\\\",\\\"https://swapi.co/api/films/6/\\\",\\\"https://swapi.co/api/films/3/\\\",\\\"https://swapi.co/api/films/1/\\\",\\\"https://swapi.co/api/films/7/\\\"],\\\"species\\\":[\\\"https://swapi.co/api/species/2/\\\"],\\\"vehicles\\\":[],\\\"starships\\\":[],\\\"created\\\":\\\"2014-12-10T15:11:50.376000Z\\\",\\\"edited\\\":\\\"2014-12-20T21:17:50.311000Z\\\",\\\"url\\\":\\\"https://swapi.co/api/people/3/\\\"}\"\n  },\n  {\n    \"type\": \"All\",\n    \"snapshots\": [\n      [\n        {\n          \"type\": \"Effect\",\n          \"effect\": {\n            \"type\": \"HttpRequest\",\n            \"url\": \"https://swapi.co/api/films/2/\"\n          },\n          \"result\": \"{\\\"title\\\":\\\"The Empire Strikes Back\\\",\\\"episode_id\\\":5,\\\"opening_crawl\\\":\\\"It is a dark time for the\\\\r\\\\nRebellion. Although the Death\\\\r\\\\nStar has been destroyed,\\\\r\\\\nImperial troops have driven the\\\\r\\\\nRebel forces from their hidden\\\\r\\\\nbase and pursued them across\\\\r\\\\nthe galaxy.\\\\r\\\\n\\\\r\\\\nEvading the dreaded Imperial\\\\r\\\\nStarfleet, a group of freedom\\\\r\\\\nfighters led by Luke Skywalker\\\\r\\\\nhas established a new secret\\\\r\\\\nbase on the remote ice world\\\\r\\\\nof Hoth.\\\\r\\\\n\\\\r\\\\nThe evil lord Darth Vader,\\\\r\\\\nobsessed with finding young\\\\r\\\\nSkywalker, has dispatched\\\\r\\\\nthousands of remote probes into\\\\r\\\\nthe far reaches of space....\\\",\\\"director\\\":\\\"Irvin Kershner\\\",\\\"producer\\\":\\\"Gary Kurtz, Rick McCallum\\\",\\\"release_date\\\":\\\"1980-05-17\\\",\\\"characters\\\":[\\\"https://swapi.co/api/people/1/\\\",\\\"https://swapi.co/api/people/2/\\\",\\\"https://swapi.co/api/people/3/\\\",\\\"https://swapi.co/api/people/4/\\\",\\\"https://swapi.co/api/people/5/\\\",\\\"https://swapi.co/api/people/10/\\\",\\\"https://swapi.co/api/people/13/\\\",\\\"https://swapi.co/api/people/14/\\\",\\\"https://swapi.co/api/people/18/\\\",\\\"https://swapi.co/api/people/20/\\\",\\\"https://swapi.co/api/people/21/\\\",\\\"https://swapi.co/api/people/22/\\\",\\\"https://swapi.co/api/people/23/\\\",\\\"https://swapi.co/api/people/24/\\\",\\\"https://swapi.co/api/people/25/\\\",\\\"https://swapi.co/api/people/26/\\\"],\\\"planets\\\":[\\\"https://swapi.co/api/planets/4/\\\",\\\"https://swapi.co/api/planets/5/\\\",\\\"https://swapi.co/api/planets/6/\\\",\\\"https://swapi.co/api/planets/27/\\\"],\\\"starships\\\":[\\\"https://swapi.co/api/starships/15/\\\",\\\"https://swapi.co/api/starships/10/\\\",\\\"https://swapi.co/api/starships/11/\\\",\\\"https://swapi.co/api/starships/12/\\\",\\\"https://swapi.co/api/starships/21/\\\",\\\"https://swapi.co/api/starships/22/\\\",\\\"https://swapi.co/api/starships/23/\\\",\\\"https://swapi.co/api/starships/3/\\\",\\\"https://swapi.co/api/starships/17/\\\"],\\\"vehicles\\\":[\\\"https://swapi.co/api/vehicles/8/\\\",\\\"https://swapi.co/api/vehicles/14/\\\",\\\"https://swapi.co/api/vehicles/16/\\\",\\\"https://swapi.co/api/vehicles/18/\\\",\\\"https://swapi.co/api/vehicles/19/\\\",\\\"https://swapi.co/api/vehicles/20/\\\"],\\\"species\\\":[\\\"https://swapi.co/api/species/6/\\\",\\\"https://swapi.co/api/species/7/\\\",\\\"https://swapi.co/api/species/3/\\\",\\\"https://swapi.co/api/species/2/\\\",\\\"https://swapi.co/api/species/1/\\\"],\\\"created\\\":\\\"2014-12-12T11:26:24.656000Z\\\",\\\"edited\\\":\\\"2017-04-19T10:57:29.544256Z\\\",\\\"url\\\":\\\"https://swapi.co/api/films/2/\\\"}\"\n        }\n      ],\n      [\n        {\n          \"type\": \"Effect\",\n          \"effect\": {\n            \"type\": \"HttpRequest\",\n            \"url\": \"https://swapi.co/api/films/7/\"\n          },\n          \"result\": \"{\\\"title\\\":\\\"The Force Awakens\\\",\\\"episode_id\\\":7,\\\"opening_crawl\\\":\\\"Luke Skywalker has vanished.\\\\r\\\\nIn his absence, the sinister\\\\r\\\\nFIRST ORDER has risen from\\\\r\\\\nthe ashes of the Empire\\\\r\\\\nand will not rest until\\\\r\\\\nSkywalker, the last Jedi,\\\\r\\\\nhas been destroyed.\\\\r\\\\n \\\\r\\\\nWith the support of the\\\\r\\\\nREPUBLIC, General Leia Organa\\\\r\\\\nleads a brave RESISTANCE.\\\\r\\\\nShe is desperate to find her\\\\r\\\\nbrother Luke and gain his\\\\r\\\\nhelp in restoring peace and\\\\r\\\\njustice to the galaxy.\\\\r\\\\n \\\\r\\\\nLeia has sent her most daring\\\\r\\\\npilot on a secret mission\\\\r\\\\nto Jakku, where an old ally\\\\r\\\\nhas discovered a clue to\\\\r\\\\nLuke's whereabouts....\\\",\\\"director\\\":\\\"J. J. Abrams\\\",\\\"producer\\\":\\\"Kathleen Kennedy, J. J. Abrams, Bryan Burk\\\",\\\"release_date\\\":\\\"2015-12-11\\\",\\\"characters\\\":[\\\"https://swapi.co/api/people/1/\\\",\\\"https://swapi.co/api/people/3/\\\",\\\"https://swapi.co/api/people/5/\\\",\\\"https://swapi.co/api/people/13/\\\",\\\"https://swapi.co/api/people/14/\\\",\\\"https://swapi.co/api/people/27/\\\",\\\"https://swapi.co/api/people/84/\\\",\\\"https://swapi.co/api/people/85/\\\",\\\"https://swapi.co/api/people/86/\\\",\\\"https://swapi.co/api/people/87/\\\",\\\"https://swapi.co/api/people/88/\\\"],\\\"planets\\\":[\\\"https://swapi.co/api/planets/61/\\\"],\\\"starships\\\":[\\\"https://swapi.co/api/starships/77/\\\",\\\"https://swapi.co/api/starships/10/\\\"],\\\"vehicles\\\":[],\\\"species\\\":[\\\"https://swapi.co/api/species/3/\\\",\\\"https://swapi.co/api/species/2/\\\",\\\"https://swapi.co/api/species/1/\\\"],\\\"created\\\":\\\"2015-04-17T06:51:30.504780Z\\\",\\\"edited\\\":\\\"2015-12-17T14:31:47.617768Z\\\",\\\"url\\\":\\\"https://swapi.co/api/films/7/\\\"}\"\n        }\n      ],\n      [...] // other API calls\n    ]\n  },\n  {\n    \"type\": \"Commit\",\n    \"commit\": {\n      \"type\": \"LoadSuccess\",\n      \"movies\": [\n        \"The Empire Strikes Back\",\n        \"Attack of the Clones\",\n        \"The Phantom Menace\",\n        \"Revenge of the Sith\",\n        \"Return of the Jedi\",\n        \"A New Hope\",\n        \"The Force Awakens\"\n      ]\n    }\n  }\n]\n```\n\n## License\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclarus%2Fredux-ship","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fclarus%2Fredux-ship","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fclarus%2Fredux-ship/lists"}