{"id":13485220,"url":"https://github.com/redux-zero/redux-zero","last_synced_at":"2025-05-14T14:07:58.278Z","repository":{"id":25680364,"uuid":"105929410","full_name":"redux-zero/redux-zero","owner":"redux-zero","description":"A lightweight state container based on Redux ","archived":false,"fork":false,"pushed_at":"2023-01-05T07:50:42.000Z","size":3227,"stargazers_count":1966,"open_issues_count":111,"forks_count":93,"subscribers_count":29,"default_branch":"master","last_synced_at":"2025-05-06T01:02:48.599Z","etag":null,"topics":["flux","functional","lightweight","preact","react","react-native","redux","small","state","svelte","typescript"],"latest_commit_sha":null,"homepage":"https://matheusml1.gitbooks.io/redux-zero-docs/content/","language":"TypeScript","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/redux-zero.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-10-05T19:07:11.000Z","updated_at":"2025-04-26T15:37:26.000Z","dependencies_parsed_at":"2023-01-14T07:00:47.409Z","dependency_job_id":null,"html_url":"https://github.com/redux-zero/redux-zero","commit_stats":null,"previous_names":["concretesolutions/redux-zero"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redux-zero%2Fredux-zero","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redux-zero%2Fredux-zero/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redux-zero%2Fredux-zero/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/redux-zero%2Fredux-zero/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/redux-zero","download_url":"https://codeload.github.com/redux-zero/redux-zero/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253253130,"owners_count":21878849,"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":["flux","functional","lightweight","preact","react","react-native","redux","small","state","svelte","typescript"],"created_at":"2024-07-31T17:01:51.620Z","updated_at":"2025-05-14T14:07:58.259Z","avatar_url":"https://github.com/redux-zero.png","language":"TypeScript","readme":"\u003ch1 align=\"center\"\u003e\n  \u003cimg src=\"https://i.imgur.com/S8jnr8O.png\" height=\"300px\" alt=\"redux zero logo\" title=\"redux zero logo\"\u003e\n  \u003cbr\u003e\n\u003c/h1\u003e\n\u003cp align=\"center\" style=\"font-size: 1.2rem;\"\u003eA lightweight state container based on Redux\u003c/p\u003e\n\n\u003e Read [the intro blog post](https://medium.com/@matheusml/introducing-redux-zero-bea42214c7ee)\n\n\u003chr /\u003e\n\n[![codacy](https://api.codacy.com/project/badge/Grade/a4adf13156bd4441ae132d2d9dc72186)](https://www.codacy.com/app/matheusml/redux-zero?utm_source=github.com\u0026utm_medium=referral\u0026utm_content=redux-zero/redux-zero\u0026utm_campaign=Badge_Grade)\n[![build](https://img.shields.io/travis/redux-zero/redux-zero/master.svg)](https://travis-ci.org/redux-zero/redux-zero)\n[![npm](https://img.shields.io/npm/v/redux-zero.svg)](https://www.npmjs.com/package/redux-zero)\n[![downloads](https://img.shields.io/npm/dm/redux-zero.svg)](https://www.npmjs.com/package/redux-zero)\n[![license](https://img.shields.io/github/license/redux-zero/redux-zero.svg)]()\n[![dependencies](https://img.shields.io/david/redux-zero/redux-zero.svg)]()\n\n## Table of Contents\n\n- [Installation](#installation)\n- [How](#how)\n- [Example](#example)\n- [Actions](#actions)\n- [Async](#async)\n- [Middleware](#middleware)\n- [DevTools](#devtools)\n- [TypeScript](#typescript)\n- [Inspiration](#inspiration)\n- [Roadmap](#roadmap)\n- [Docs](#docs)\n\n## Installation\n\nTo install the stable version:\n\n```\nnpm i redux-zero\n```\n\nThis assumes that you’re using [npm](https://www.npmjs.com/) with a module bundler like [webpack](https://webpack.js.org/)\n\n## How\n\n**ES2015+:**\n\n```js\nimport createStore from \"redux-zero\";\nimport { Provider, connect } from \"redux-zero/react\";\n```\n\n**TypeScript:**\n\n```js\nimport * as createStore from \"redux-zero\";\nimport { Provider, connect } from \"redux-zero/react\";\n```\n\n**CommonJS:**\n\n```js\nconst createStore = require(\"redux-zero\");\nconst { Provider, connect } = require(\"redux-zero/react\");\n```\n\n**UMD:**\n\n```html\n\u003c!-- the store --\u003e\n\u003cscript src=\"https://unpkg.com/redux-zero/dist/redux-zero.min.js\"\u003e\u003c/script\u003e\n\n\u003c!-- for react --\u003e\n\u003cscript src=\"https://unpkg.com/redux-zero/react/index.min.js\"\u003e\u003c/script\u003e\n\n\u003c!-- for preact --\u003e\n\u003cscript src=\"https://unpkg.com/redux-zero/preact/index.min.js\"\u003e\u003c/script\u003e\n\n\u003c!-- for vue --\u003e\n\u003cscript src=\"https://unpkg.com/redux-zero/vue/index.min.js\"\u003e\u003c/script\u003e\n\n\u003c!-- for svelte --\u003e\n\u003cscript src=\"https://unpkg.com/redux-zero/svelte/index.min.js\"\u003e\u003c/script\u003e\n```\n\n## Example\n\nLet's make an increment/decrement simple application with React:\n\nFirst, create your store. This is where your application state will live:\n\n```js\n/* store.js */\nimport createStore from \"redux-zero\";\n\nconst initialState = { count: 1 };\nconst store = createStore(initialState);\n\nexport default store;\n```\n\nThen, create your actions. This is where you change the state from your store:\n\n```js\n/* actions.js */\nconst actions = store =\u003e ({\n  increment: state =\u003e ({ count: state.count + 1 }),\n  decrement: state =\u003e ({ count: state.count - 1 })\n});\n\nexport default actions;\n```\n\nBy the way, because the actions are bound to the store, they are just pure functions :)\n\nNow create your component. With **Redux Zero** your component can focus 100% on the UI and just call the actions that will automatically update the state:\n\n```js\n/* Counter.js */\nimport React from \"react\";\nimport { connect } from \"redux-zero/react\";\n\nimport actions from \"./actions\";\n\nconst mapToProps = ({ count }) =\u003e ({ count });\n\nexport default connect(\n  mapToProps,\n  actions\n)(({ count, increment, decrement }) =\u003e (\n  \u003cdiv\u003e\n    \u003ch1\u003e{count}\u003c/h1\u003e\n    \u003cdiv\u003e\n      \u003cbutton onClick={decrement}\u003edecrement\u003c/button\u003e\n      \u003cbutton onClick={increment}\u003eincrement\u003c/button\u003e\n    \u003c/div\u003e\n  \u003c/div\u003e\n));\n```\n\nLast but not least, plug the whole thing in your index file:\n\n```js\n/* index.js */\nimport React from \"react\";\nimport { render } from \"react-dom\";\nimport { Provider } from \"redux-zero/react\";\n\nimport store from \"./store\";\n\nimport Counter from \"./Counter\";\n\nconst App = () =\u003e (\n  \u003cProvider store={store}\u003e\n    \u003cCounter /\u003e\n  \u003c/Provider\u003e\n);\n\nrender(\u003cApp /\u003e, document.getElementById(\"root\"));\n```\n\nHere's the full version: [https://codesandbox.io/s/n5orzr5mxj](https://codesandbox.io/s/n5orzr5mxj)\n\nBy the way, you can also reset the state of the store anytime by simply doing this:\n\n```js\nimport store from \"./store\";\n\nstore.reset();\n```\n\n### More examples\n\n- [React](https://github.com/redux-zero/redux-zero/tree/master/examples/react/counter)\n- [React-Router](https://github.com/redux-zero/redux-zero/tree/master/examples/react/react-router)\n- [Material-UI](https://github.com/redux-zero/redux-zero/tree/master/examples/react/material-ui-counter)\n- [Preact](https://github.com/redux-zero/redux-zero/tree/master/examples/preact/counter)\n- [React Native](https://github.com/redux-zero/redux-zero/tree/master/examples/react-native/counter)\n- [SSR](https://github.com/redux-zero/redux-zero/tree/master/examples/react/ssr)\n- [Svelte](https://github.com/redux-zero/redux-zero/tree/master/examples/svelte/counter)\n- [Vue](https://github.com/redux-zero/redux-zero/tree/master/examples/vue/counter)\n\n## Actions\n\nThere are three gotchas with Redux Zero's actions:\n\n- Passing arguments\n- Combining actions\n- Binding actions outside your application scope\n\n### Passing arguments\n\nHere's how you can pass arguments to actions:\n\n```js\nconst Component = ({ count, incrementOf }) =\u003e (\n  \u003ch1 onClick={() =\u003e incrementOf(10)}\u003e{count}\u003c/h1\u003e\n);\n\nconst mapToProps = ({ count }) =\u003e ({ count });\n\nconst actions = store =\u003e ({\n  incrementOf: (state, value) =\u003e ({ count: state.count + value })\n});\n\nconst ConnectedComponent = connect(\n  mapToProps,\n  actions\n)(Component);\n\nconst App = () =\u003e (\n  \u003cProvider store={store}\u003e\n    \u003cConnectedComponent /\u003e\n  \u003c/Provider\u003e\n);\n```\n\n### Access props in actions\n\nThe initial component props are passed to the actions creator.\n\n```js\nconst Component = ({ count, increment }) =\u003e (\n  \u003ch1 onClick={() =\u003e increment()}\u003e{count}\u003c/h1\u003e\n);\n\nconst mapToProps = ({ count }) =\u003e ({ count });\n\nconst actions = (store, ownProps) =\u003e ({\n  increment: state =\u003e ({ count: state.count + ownProps.value })\n});\n\nconst ConnectedComponent = connect(\n  mapToProps,\n  actions\n)(Component);\n\nconst App = () =\u003e (\n  \u003cProvider store={store}\u003e\n    \u003cConnectedComponent value={10} /\u003e\n  \u003c/Provider\u003e\n);\n```\n\n### Combining actions\n\nThere's an utility function to combine actions on Redux Zero:\n\n```js\nimport { connect } from \"redux-zero/react\";\nimport { combineActions } from \"redux-zero/utils\";\n\nimport Component from \"./Component\";\nimport firstActions from \"../../actions/firstActions\";\nimport secondActions from \"../../actions/secondActions\";\n\nexport default connect(\n  ({ params, moreParams }) =\u003e ({ params, moreParams }),\n  combineActions(firstActions, secondActions)\n)(Component);\n```\n\n### Binding actions outside your application scope\n\nIf you need to bind the actions to an external listener outside the application scope, here's a simple way to do it:\n\nOn this example we listen to push notifications that sends data to our React Native app.\n\n```js\nimport firebase from \"react-native-firebase\";\nimport { bindActions } from \"redux-zero/utils\";\nimport store from \"../store\";\nimport actions from \"../actions\";\n\nconst messaging = firebase.messaging();\nconst boundActions = bindActions(actions, store);\n\nmessaging.onMessage(payload =\u003e {\n  boundActions.saveMessage(payload);\n});\n```\n\n## Async\n\nAsync actions in Redux Zero are almost as simple as sync ones. Here's an example:\n\n```js\nconst mapActions = ({ setState }) =\u003e ({\n  getTodos() {\n    setState({ loading: true });\n\n    return client\n      .get(\"/todos\")\n      .then(payload =\u003e ({ payload, loading: false }))\n      .catch(error =\u003e ({ error, loading: false }));\n  }\n});\n```\n\nThey're still pure functions. You'll need to invoke `setState` if you have a loading status. But at the end, it's the same, just return whatever the updated state that you want.\n\nAnd here's how easy it is to test this:\n\n```js\ndescribe(\"todo actions\", () =\u003e {\n  let actions, store, listener, unsubscribe;\n  beforeEach(() =\u003e {\n    store = createStore();\n    actions = getActions(store);\n    listener = jest.fn();\n    unsubscribe = store.subscribe(listener);\n  });\n\n  it(\"should fetch todos\", () =\u003e {\n    nock(\"http://someapi.com/\")\n      .get(\"/todos\")\n      .reply(200, { id: 1, title: \"test stuff\" });\n\n    return actions.getTodos().then(() =\u003e {\n      const [LOADING_STATE, SUCCESS_STATE] = listener.mock.calls.map(\n        ([call]) =\u003e call\n      );\n\n      expect(LOADING_STATE.loading).toBe(true);\n      expect(SUCCESS_STATE.payload).toEqual({ id: 1, title: \"test stuff\" });\n      expect(SUCCESS_STATE.loading).toBe(false);\n    });\n  });\n});\n```\n\n## Middleware\n\nThe method signature for the middleware was inspired by redux. The main difference is that action is just a function:\n\n```js\n/* store.js */\nimport createStore from \"redux-zero\";\nimport { applyMiddleware } from \"redux-zero/middleware\";\n\nconst logger = store =\u003e (next, args) =\u003e action =\u003e {\n  console.log(\"current state\", store.getState());\n  console.log(\"action\", action.name, ...args);\n  return next(action);\n};\n\nconst initialState = { count: 1 };\nconst middlewares = applyMiddleware(logger, anotherMiddleware);\n\nconst store = createStore(initialState, middlewares);\n\nexport default store;\n```\n\n## DevTools\n\nYou can setup DevTools middleware in store.js to connect with Redux DevTools and inspect states in the store.\n\n```js\n/* store.js */\nimport createStore from \"redux-zero\";\nimport { applyMiddleware } from \"redux-zero/middleware\";\nimport { connect } from \"redux-zero/devtools\";\n\nconst initialState = { count: 1 };\nconst middlewares = connect ? applyMiddleware(connect(initialState)) : [];\nconst store = createStore(initialState, middlewares);\n\nexport default store;\n```\n\nAlso, these are unofficial tools, maintained by the community:\n\n- [Redux-Zero Tools](https://github.com/nyteshade/rzero-tools)\n- [redux-zero persist middleware](https://github.com/axetroy/redux-zero-persist)\n- [redux-zero logger middleware](https://github.com/axetroy/redux-zero-logger)\n- [redux loading middleware](https://github.com/andre-araujo/redux-loading-middleware)\n\n## TypeScript\n\nYou can use the `BoundActions` type to write your React component props in a type\nsafe way. Example:\n\n```typescript\nimport { BoundActions } from \"redux-zero/types/Actions\";\n\ninterface State {\n  loading: boolean;\n}\n\nconst actions = (store, ownProps) =\u003e ({\n  setLoading: (state, loading: boolean) =\u003e ({ loading })\n});\n\ninterface ComponentProps {\n  value: string;\n}\n\ninterface StoreProps {\n  loading: boolean;\n}\n\ntype Props = ComponentProps \u0026 StoreProps \u0026 BoundActions\u003cState, typeof actions\u003e\n\nconst Component = (props: Props) =\u003e (\n  \u003ch1 onClick={() =\u003e props.setLoading(!props.loading)}\u003e{props.value}\u003c/h1\u003e\n);\n\nconst mapToProps = (state: State): StoreProps =\u003e ({ loading: state.loading });\n\nconst ConnectedComponent = connect\u003cState, ComponentProps\u003e(\n  mapToProps,\n  actions\n)(Component);\n\nconst App = () =\u003e (\n  \u003cProvider store={store}\u003e\n    \u003cConnectedComponent value={10} /\u003e\n  \u003c/Provider\u003e\n);\n```\n\nBy doing this, TypeScript will know the available actions and their types\navailable on the component's props. For example, you will get a compiler error if you\ncall `props.setLoding` (that action doesn't exist), or if you call it\nwith incorrect argument types, like `props.setLoading(123)`.\n\n## Inspiration\n\n**Redux Zero** was based on this [gist](https://gist.github.com/developit/55c48d294abab13a146eac236bae3219) by [@developit](https://github.com/developit)\n\n## Roadmap\n\n- Make sure all bindings are working for latest versions of React, Vue, Preact and Svelte\n- Add time travel\n\n_Help is needed for both of these_\n\n## Docs\n\n- [Full Docs](https://matheusml1.gitbooks.io/redux-zero-docs/content/)\n- [Contributing](https://github.com/redux-zero/redux-zero/blob/master/CONTRIBUTING.md)\n- [Changelog](https://github.com/redux-zero/redux-zero/blob/master/CHANGELOG.md)\n- [Code of Conduct](https://github.com/redux-zero/redux-zero/blob/master/CODE_OF_CONDUCT.md)\n- [License](https://github.com/redux-zero/redux-zero/blob/master/LICENSE)\n","funding_links":[],"categories":["TypeScript","List"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredux-zero%2Fredux-zero","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fredux-zero%2Fredux-zero","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fredux-zero%2Fredux-zero/lists"}