{"id":19214321,"url":"https://github.com/fullstackreact/redux-modules","last_synced_at":"2025-05-12T22:21:12.264Z","repository":{"id":57351041,"uuid":"59609257","full_name":"fullstackreact/redux-modules","owner":"fullstackreact","description":"A better redux module helper","archived":false,"fork":false,"pushed_at":"2017-01-13T11:57:54.000Z","size":484,"stargazers_count":59,"open_issues_count":4,"forks_count":9,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-20T19:36:59.603Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://fullstackreact.github.io/redux-modules/","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/fullstackreact.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-05-24T21:17:16.000Z","updated_at":"2022-11-17T21:21:19.000Z","dependencies_parsed_at":"2022-09-18T23:03:22.040Z","dependency_job_id":null,"html_url":"https://github.com/fullstackreact/redux-modules","commit_stats":null,"previous_names":[],"tags_count":9,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fullstackreact%2Fredux-modules","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fullstackreact%2Fredux-modules/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fullstackreact%2Fredux-modules/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/fullstackreact%2Fredux-modules/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/fullstackreact","download_url":"https://codeload.github.com/fullstackreact/redux-modules/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253831219,"owners_count":21971051,"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-09T14:09:36.395Z","updated_at":"2025-05-12T22:21:12.244Z","avatar_url":"https://github.com/fullstackreact.png","language":"JavaScript","readme":"## Redux modules\n\nThe `redux-modules` package offers a different method of handling [redux](http://redux.js.org/) module packaging.\n\nThe overall idea behind `redux-modules` is to build all of the corresponding redux functionality, constants, reducers, actions in a common location that makes it easy to understand the entire workflow common to a component of an application.\n\nRedux modules is essentially a collection of helpers that provide functionality for common tasks related to using Redux.\n\n## Quick take\n\nA redux module enables us to build our redux modules in a simple manner. A redux module can be as simple as:\n\n```javascript\n/**\n * Creates a `types` object\n * with the hash of constants\n **/\nconst types = createConstants({\n  prefix: 'TODO'\n})(\n  'CREATE',\n  'MARK_DONE',\n  'FETCH_ALL': {api: true}\n);\n\n/**\n * The root reducer that handles only create\n **/\nconst reducer = createReducer({\n  [types.CREATE]: (state, {payload}) =\u003e ({\n    ...state,\n    todos: state.todos.concat(payload)\n  }),\n\n  // decorator form\n  @apiHandler(types.FETCH_ALL, (apiTypes) =\u003e {\n    // optional overrides\n    [apiTypes.FETCH_ALL_LOADING]: (state, action) =\u003e ({...state, loading: true})\n  })\n  handleFetchAll: (state, action) =\u003e ({...state, todos: action.payload})\n\n  // or non-decorator form:\n  handleFetchAll: createApiHandler(types.FETCH_ALL)((state, action) =\u003e {\n    return {...state, todos: action.payload};\n  })\n})\n\n/**\n * Actions\n **/\nconst actions = createActions({\n  createTodo: (text) =\u003e (dispatch) =\u003e dispatch({\n    type: types.CREATE,\n    payload: {text: text, done: false}\n  }),\n\n  // decorator form\n  @api(types.FETCH_ALL)\n  fetchAll: (client, opts) =\u003e client.get({path: '/todos'})\n\n  // or non-decorator form\n  fetchAll: createApiAction(types.FETCH_ALL)((client, opts) =\u003e {\n    return () =\u003e (dispatch, getState) =\u003e client.get('/todos')\n  })\n})\n```\n\nIn our app, our entire todo handler, reducer, and actions are all in one place in a single file. Incorporating the handler, reducer, and actions in our redux app is up to you. See [Usage in Redux](#usage-with-react-redux) for information.\n\n## Installation\n\n```bash\nnpm install --save redux-module-builder\n```\n\n## Example\n\nFor example, let's take the idea of writing a TODO application. We'll need a few actions:\n\n* Create\n* Mark done\n* Fetch All\n\nUsing `redux-modules`, we can create an object that carries a unique _type_ string for each of the actions in namespace path on a type object using the `createConstants()` exported method. For instance:\n\n```javascript\nconst types = createConstants('TODO')({\n  'CREATE': true, // value is ignored\n  'FETCH_ALL': {api: true}\n})\n```\n\n\u003cdiv id=\"constantExample\"\u003e\u003c/div\u003e\n\nIf you prefer not to use any of the api helpers included with `redux-modules`, the `createConstants()` function accepts a simple list of types instead:\n\n```javascript\nconst types = createConstants('TODO')(\n  'CREATE', 'MARK_DONE', 'DELETE'\n)\n```\n\n## createReducer\n\nThe `createReducer()` exported function is a simple reduce handler. It accepts a single object and is responsible for passing action handling down through defined functions on a per-action basis.\n\nThe first argument object is the list of handlers, by their type with a function to be called on the dispatch of the action. For instance, from our TODO example, this object might look like:\n\n```javascript\nconst reducer = createReducer({\n  [types.CREATE]: (state, {payload}) =\u003e ({\n    ...state,\n    todos: state.todos.concat(payload)\n  })\n});\n```\n\nThe previous object defines a handler for the `types.CREATE` action type, but does not define one for the `types.FETCH_ALL`. When the `types.CREATE` type is dispatched, the function above runs and is considered the reducer for the action. In this example, when the `types.FETCH_ALL` action is dispatched, the default handler: `(state, action) =\u003e state` is called (aka the original state).\n\nTo add handlers, we only need to define the key and value function.\n\n## API handling\n\nThe power of `redux-modules` really comes into play when dealing with async code. The common pattern of handling async API calls, which generates multiple states.\n\nNotice in our above example we can mark types as `api: true` within a type object and notice that it created 4 action key/values in the object which correspond to different states of an api call (loading, success, error, and the type itself). We can use this pattern to provide simple api handling to any action/reducer.\n\n### apiMiddleware\n\nIn order to set this up, we need to add a middleware to our redux stack. This middleware helps us define defaults for handling API requests. For instance. In addition, `redux-modules` depends upon [redux-thunk](https://github.com/gaearon/redux-thunk) being available as a middleware _after_ the apiMiddleware.\n\nFor instance:\n\n```javascript\n// ...\nlet todoApp = combineReducers(reducers)\nlet apiMiddleware = createApiMiddleware({\n                      baseUrl: `https://fullstackreact.com`,\n                      headers: {}\n                    });\nlet store = createStore(reducers,\n            applyMiddleware(apiMiddleware, thunk));\n// ...\n```\n\nThe object the `createApiMiddleware()` accepts is the default configuration for all API requests. For instance, this is a good spot to add custom headers, a `baseUrl` (required), etc. Whatever we pass in here is accessible across every api client.\n\nFor more _dynamic_ requests, we can pass a function into any one of these options and it will be called with the state so we can dynamically respond. An instance where we might want to pass a function would be with our headers, which might respond with a token for every request. Another might be a case for A/B testing where we can dynamically assign the `baseUrl` on a per-user basis.\n\n```javascript\n// dynamically adding headers for _every_ request:\nlet apiMiddleware = createApiMiddleware({\n                      baseUrl: `https://fullstackreact.com`,\n                      headers: (state) =\u003e ({\n                        'X-Auth-Token': state.user.token\n                      })\n                    });\n```\n\nThe `apiMiddleware` above currently decorates an actions `meta` object. For instance:\n\n```javascript\n{\n  type: 'API_FETCH_ALL',\n  payload: {},\n  meta: {isApi: true}\n}\n// passes to the `thunk` middleware the resulting action:\n{\n  type: 'API_FETCH_ALL',\n  payload: {},\n  meta: {\n    isApi: true,\n    baseUrl: BASE_URL,\n    headers: {}\n  }\n}\n```\n\n### apiActions\n\nThe easiest way to take advantage of this api infrastructure is to decorate the actions with the `@api` decorator (or the non-decorator form `createApiAction()`). When calling an api action created with the `@api/createApiAction`, `redux-modules` will dispatch two actions, the loading action and the handler.\n\nThe `loading` action is fired with the type `[NAMESPACE]_loading`. The second action it dispatches is the handler function. The method that it is decorated with is expected to return a promise (although `redux-modules` will convert the response to a promise if it's not already one) which is expected to resolve in the case of success and error otherwise.\n\nMore conveniently, `redux-modules` provides a client instance of [ApiClient](https://github.com/fullstackreact/redux-modules/blob/master/src/lib/apiClient.js) for every request (which is a thin wrapper around `fetch`).\n\n```javascript\n// actions\n@api(types.FETCH_ALL)\nfetchAll: (client, opts) =\u003e {\n  return client.get({\n    path: '/news'\n  }).then((json) =\u003e {\n    return json;\n  });\n}\n```\n\nThe `apiClient` includes handling for request transformations, status checking, and response transformations. We'll look at those in a minute. The `apiClient` instance includes the HTTP methods:\n\n* GET\n* POST\n* PUT\n* PATCH\n* DELETE\n* HEAD\n\nThese methods can be called on the client itself:\n\n```javascript\nclient.get({})\nclient.post({})\nclient.put({})\n```\n\nWhen they are called, they will be passed a list of options, which includes the base options (passed by the middleware) combined with custom options passed to the client (as the first argument).\n\n#### api client options\n\nThe `apiClient` methods accept an argument of options for a per-api request customization. The following options are available and each can be either an atomic value or a function which gets called with the api request options within the client itself _or_ in the `baseOpts` of the middleware.\n\nWhen defining these options in the middleware, keep in mind that they will be available for every request passed by the `client` instance.\n\n1. path\n\nIf a `path` option is found, `apiClient` will append the path to the `baseUrl`. If the `client` is called with a single _string_ argument, then it is considered the `path`. For instance:\n\n```javascript\n// the following are equivalent\nclient.get('/foo')\nclient.get({path: '/foo'})\n// each results in a GET request to [baseUrl]/foo\n```\n\n2. url\n\nTo completely ignore the `baseUrl` for a request, we can pass the `url` option which is used for the request.\n\n```javascript\nclient.get({url: 'http://google.com/?q=fullstackreact'})\n```\n\n3. appendPath\n\nFor dynamic calls, sometimes it's convenient to add a component to the path. For instance, we might want to append the url with a custom session key.\n\n```javascript\nclient.get({appendPath: 'abc123'})\n```\n\n4. appendExt\n\nThe `appendExt` is primarily useful for padding extensions on a url. For instance, to make all requests to the url with the `.json` extension, we can pass the `appendExt` to json:\n\n```javascript\nclient.get({appendExt: 'json'})\n```\n\n5. params\n\nThe `params` option is a query-string list of parameters that will be passed as query-string options.\n\n```javascript\nclient.get({params: {q: 'fullstackreact'}})\n```\n\n6. headers\n\nEvery request can define their own headers (or globally with the middleware) by using the `headers` option:\n\n```javascript\nclient.get({headers: {'X-Token': 'bearer someTokenThing'}})\n```\n\n#### transforms\n\nThe request and response transforms provide a way to manipulate requests as they go out and and they return. These are functions that are called with the `state` as well as the current request options.\n\n#### requestTransforms\n\nRequest transforms are functions that can be defined to create a dynamic way to manipulate headers, body, etc. For instance, if we want to create a protected route, we can use a requestTransform to append a custom header.\n\n```javascript\nclient.get({\n  requestTransforms: [(state, opts) =\u003e req =\u003e {\n    req.headers['X-Name'] = 'Ari';\n    return req;\n  }]\n})\n```\n\n#### responseTransforms\n\nA response transform handles the resulting request response and gives us an opportunity to transform the data to another format on the way in. The default response transform is to respond with the response body into json. To handle the actual response, we can assign a responseTransform to overwrite the default json parsing and get a handle on the actual fetch response.\n\n```javascript\nlet timeTransform = (state, opts) =\u003e res =\u003e {\n  res.headers.set('X-Response-Time', time);\n  return res;\n}\nlet jsonTransform = (state, opts) =\u003e (res) =\u003e {\n  let time = res.headers.get('X-Response-Time');\n  return res.json().then(json =\u003e ({...json, time}))\n}\nclient.get({\n  responseTransforms: [timeTransform, jsonTransform]\n})\n```\n\nFor apis that do not respond with json, the `responseTransforms` are a good spot to handle conversion to another format, such as xml.\n\n### apiHandlers\n\nTo handle api responses in a reducer, `redux-modules` provides the `apiHandler` decorator (and it's non-decorator form: `createApiHandler()`). This decorator provides a common interface for handling the different states of an api request (i.e. `loading`, `success`, and `error` states).\n\n```javascript\n@apiHandler(types.FETCH_ALL)\nhandleFetchAll: (state, {payload}) =\u003e {...state, ...payload}\n```\n\nThe decorated function is considered the _success_ function handler and will be called upon a success status code returned from the request.\n\nTo handle custom loading states, we can \"hook\" into them with a second argument. The second argument is a function that's called with the dynamic states provided by the argument it's called with. For instance, to handle custom handling of an error state:\n\n```javascript\n@apiHandler(types.FETCH_ALL, (apiTypes) =\u003e ({\n  [apiTypes.ERROR]: (state, {payload}) =\u003e ({\n    ...state,\n    error: payload.body.message,\n    loading: false\n  })\n}))\nhandleFetchAll: (state, {payload}) =\u003e {...state, ...payload}\n```\n\n## Usage with react-redux\n\nThere are multiple methods for combining `redux-modules` with react and this is our opinion about how to use the two together.\n\nFirst, our directory structure generally sets all of our modules in their own directory:\n\n```bash\nindex.js\n  /redux\n    /modules/\n      todo.js\n      users.js\n    configureStore.js\n    rootReducer.js\n    index.js\n```\n\nConfiguring the store for our app is straight-forward. First, we'll apply the `createApiMiddleware()` before we create the final store. In a `configureStore.js` file, we like to handle creating a store in a single spot. We'll export a function to configure the store:\n\n```javascript\nimport {rootReducer, actions} from './rootReducer'\n\nexport const configureStore = ({initialState = {}}) =\u003e {\n  let middleware = [\n    createApiMiddleware({\n      baseUrl: BASE_URL\n    }),\n    thunkMiddleware\n  ]\n  // ...\n  const finalCreateStore =\n        compose(applyMiddleware(...middleware))(createStore);\n\n  const store = finalCreateStore(rootReducer, initialState);\n  // ...\n}\n```\n\nThis creates the middleware for us. Next, we like to combine our actions into a single actions object that we'll pass along down through our components. We'll use the `bindActionCreatorsToStore()` export to build our action creators and bind them to the store.\n\nWe'll need to bind our actions to the store, so that when we call dispatch it will use our store's dispatch (see [react-redux](https://github.com/reactjs/react-redux)). Just after we create the store, we'll:\n\n```javascript\nlet actions = bindActionCreatorsToStore(actions, store);\n```\n\nFrom here, we just return the store and actions from the function:\n\n```javascript\nexport const configureStore = ({initialState = {}}) =\u003e {\n  // ...\n  const store = finalCreateStore(rootReducer, initialState);\n  // ...\n  let actions = bindActionCreatorsToStore(actions, store);\n\n  return {store, actions};\n}\n```\n\nNow that the heavy-lifting is done, the `rootReducer.js` file is pretty simple. We export all the actions and reducers pretty simply:\n\n```javascript\nconst containers = ['users', 'todos'];\n\nexport const reducers = {}\nexport const actions = {};\n\ncontainers.forEach(k =\u003e {\n  let val = require(`./modules/${v}`);\n  reducers[k] = val.reducer;\n  actions[k] = val.actions || {};\n});\n\nexport const rootReducer = combineReducers(reducers);\n```\n\nFrom here, our main container can pass the store and actions as props to our components:\n\n```javascript\nconst {store, actions} = configureStore({initialState});\n// ...\nReactDOM.render(\n  \u003cContainer store={store}, actions={actions} /\u003e,\n  node);\n```\n\nNow, anywhere in our code, we can refer to the actions we export in our modules by their namespace. For instance, to call the `createTodo()` function, we can reference it by the prop namespace:\n\n```javascript\nclass Container extends React.Component {\n\n  createTodo() {\n    const {actions} = this.props;\n    // form: actions.[namespace].[actionName]();\n    actions.todos.createTodo(\"Finish this text\");\n  }\n\n  render() {\n    return (\n      \u003cdiv onClick={this.createTodo.bind(this)}\u003e\n        Create todo\n      \u003c/div\u003e\n    )\n  }\n}\n```\n\n## Combining usage with `ducks-modular-redux`\n\n`redux-modules` plays nicely with other redux packages as well. For instance, the `ducks-modular-redux` package defines a specific method of handling actions, reducers, and types.\n\nTo create types in the same way, we can use the `separator` and `prefix` options in `createConstants()`. For instance, to create the constants defined by `ducks-modular-redux`'s README':\n\n```javascript\nconst LOAD   = 'my-app/widgets/LOAD';\nconst CREATE = 'my-app/widgets/CREATE';\nconst UPDATE = 'my-app/widgets/UPDATE';\nconst REMOVE = 'my-app/widgets/REMOVE';\n// In redux-modules:\nconst types = createConstants({\n  prefix: ['my-app', 'widgets'],\n  separator: '/'\n})('LOAD', 'CREATE', 'UPDATE', 'REMOVE')\n```\n\nHandling the reducer function is similarly easy as well:\n\n```javascript\nexport default function reducer(state = {}, action = {}) {\n  switch (action.type) {\n    // do reducer stuff\n    default: return state;\n  }\n}\nconst reducer = createReducer({\n  [types.LOAD]: (state, {payload}) =\u003e ({\n    ...state,\n    todos: state.todos.concat(payload)\n  }),\n  // ...\n});\n```\n\nFinally, exporting functions individually from the file is directly supported. The `createActions()` and `createApiAction()` helpers can be used directly on created functions.\n\n## All exports\n\nThe `redux-modules` comprises the following exports:\n\n### createConstants\n\n`createConstants()` creates an object to handle creating an object of type constants. It allows for multiple types to be dynamically created with their own custom prefixing, created on a single object.\n\n```javascript\nconst types = createConstants({})('DOG', 'CAT');\n```\n\nOptions:\n\n* prefix (string/array, default: '')\n\nThe `prefix` option creates each type with a predefined prefix.\n\n```javascript\nconst types = createConstants({\n  prefix: 'animals'\n})('DOG', 'CAT')\nexpect(types.DOG).to.eql('ANIMALS_DOG');\nexpect(types.CAT).to.eql('ANIMALS_CAT');\n\nconst types = createConstants({\n  prefix: ['test', 'animals']\n})('DOG', 'CAT')\nexpect(types.DOG).to.eql('TEST_ANIMALS_DOG');\nexpect(types.CAT).to.eql('TEST_ANIMALS_CAT');\n```\n\n* separator (string, default: `_`)\n\nThe separator option allows us to change the way prefixes are concatenated. To change the separator to use a `/`, add the separator option:\n\n```javascript\nconst types = createConstants({\n  separator: '/',\n  prefix: ['test', 'animals']\n})('DOG', 'CAT')\nexpect(types.DOG).to.eql('TEST/ANIMALS/DOG');\nexpect(types.CAT).to.eql('TEST/ANIMALS/CAT');\n```\n\n* initialObject (object, default: `{}`)\n\nFor the case where you want to define types on an existing object, `createConstants()` accepts an `initialObject` to add the types. This allows us to create a single global object (for instance) to define all of our types.\n\n```javascript\nconst types = createConstants({\n  initialObject: types\n})('OTHER', 'CONSTANTS');\n```\n\n### createReducer\n\nThe `createReducer()` function returns a function that acts similar to the switch-case functionality of redux where we'll define the types and the reducers that handle the types.\n\n```javascript\nconst reducer = createReducer({\n  [types.CREATE]: (state, {payload}) =\u003e ({\n    ...state,\n    todos: state.todos.concat(payload)\n  })\n});\n```\n\n### bindActionCreatorsToStore\n\nThe `bindActionCreatorsToStore()` function accepts two arguments, the action handler object and the store object. It takes each action, binds the function to the `store` object (so `this` refers to the `store`) and then calls the `bindActionCreators()` redux function to the store object. Use the returned value as the reducer object.\n\n```javascript\nlet actions = bindActionCreatorsToStore(actions, store);\n```\n\n### createApiMiddleware\n\nIn order to set global options for every api request, we have to include a middleware in our stack. Creating the middleware for our redux stack uses `createApiMiddleware()` and essentially looks for any api action (with `meta.isApi` set to true) and merges global options into the `meta` key of the action.\n\nWe _must_ set the `baseUrl` in the middleware, which is used as the default url to make a request against. Without the `baseUrl`, all requests will be sent without an http component (unless set otherwise in the `apiClient`):\n\n```javascript\nlet apiMiddleware = createApiMiddleware({\n                      baseUrl: `https://fullstackreact.com`,\n                      headers: {\n                        'Accept': 'application/json'\n                      }\n                    });\n```\n\n### apiClient\n\nThe `apiClient` is a loose wrapper around the native html5 `fetch()` function (built around `isomorphic-fetch`, which makes testing easier). When an action is marked as an API action, it will be called with an instance of the `apiClient` as well as the options `fetch()` will be called with. This gives us an easy, flexible way to make API requests.\n\nThe `apiClient` instance creates methods for each HTTP method, which accepts custom parameters to make the requests. It handles building the request, the options, putting together the url, packaging the body, request and response transformations, and more.\n\nUsing the `apiClient` instance inside of an api action request looks like:\n\n```javascript\n@api(types.FETCH_ALL)\nfetchAll: (client, opts) =\u003e client.get({path: '/todos'})\n// or non-decorator version\nlet decoratedFetchall = createApiAction(types.FETCH_ALL)(function(client, opts) {\n  return client.get({path: '/todos'})\n});\n```\n\nBy default, the request is assumed to be in json format, but this is flexible and can be manipulated on a global/per-request level.\n\nEvery option that the `apiMiddleware` and `apiClient.[method]` accepts can be either an atomic value or it can be a function. If a function is passed, it will be called at runtime with the current options and state to allow for dynamic responses based upon the state.\n\nThe available options for _both_ apiMiddleware and client method requests are [here](#api-client-options).\n\n### createApiAction/@api\n\nTo create an api action creator, we can decorate it with the `@api` decorator (when defined inline in an object) or using the `createApiAction()` function. Using this decorator, the function itself will be used to fetch an api.\n\nThe decorated function is expected to use the `client`, although it is not required. It is expected that the decorated function returns a value, either a promise or an atomic value.\n\n```javascript\n{\n  actions: {\n    @api(types.FETCH_ALL)\n    fetchAll: (client, opts) =\u003e client.get({path: '/todos'})\n  }\n}\n// OR non-decorator version\nconst fetchAll = createApiAction(types.FETCH_ALL)(\n  (client, opts) =\u003e client.get('/todos'));\n```\n\nUsing the decorator will dispatch actions according to their response status, first dispatching the `loading` type (i.e. `{type: 'API_FETCH_ALL_LOADING', opts}`), then it calls the handler. Once the handler returns, the corresponding action `_SUCCESS` or `_ERROR` action types are dispatched.\n\n### createApiHandler/@apiHandler\n\nIn order to handle the response from an api request, we need to create a reducer. The `api` decorator fires the status values for the state of the api request. Using the `createApiHandler()/@apiHandler` decorator sets up default handlers for dealing with these responses.\n\n```javascript\n{\n  reducers: {\n    @apiHandler(types.FETCH_ALL)\n    handleFetchAll: (state, action) =\u003e ({...state, ...action.payload});\n  }\n}\n// or non-decorator version\nconst handlers = createApiHandler(types.FETCH_ALL) =\u003e {})((state, action) =\u003e {\n  return {\n    ...state,\n    ...action.payload\n  }  \n});\n```\n\nThe default actions will set the `loading` flag to true when the `_LOADING` action type is called, while the `loading` flag (in the state) will be set to false for the `_ERROR` and `_SUCCESS` types.\n\nFor the case where we want to handle the states in a custom way, we can pass a second argument as a function which is called with the api states object where we can set custom handlers. For instance, to handle loading and errors in our previous example:\n\n```javascript\n{\n  reducers: {\n    @apiHandler(types.FETCH_ALL, (apiStates) =\u003e {\n      [apiStates.loading]: (state, action) =\u003e ({...state, loading: true}),\n      [apiStates.error]: (state, action) =\u003e {\n        return ({\n          ...state,\n          error: action.payload\n        })\n      }\n    })\n    handleFetchAll: (state, action) =\u003e ({...state, ...action.payload});\n  }\n}\n```\n\nThe decorated function is considered the success handler.\n\n## TODOS:\n\n* [x] Use the custom type creator in `createConstants()` for defining apis\n* [] Add docs for `createRootReducer()`\n\n## Contributing\n\n```shell\ngit clone https://github.com/fullstackreact/redux-modules.git\ncd redux-modules\nnpm install\nmake dev\n```\n\nTo run the tests (please ensure the tests pass when creating a pull request):\n\n```shell\nmake test # or npm run test\n```\n\n___\n\n# Fullstack React Book\n\n\u003ca href=\"https://fullstackreact.com\"\u003e\n\u003cimg align=\"right\" src=\"https://github.com/fullstackreact/google-maps-react/raw/master/resources/readme/fullstack-react-hero-book.png\" alt=\"Fullstack React Book\" width=\"155\" height=\"250\" /\u003e\n\u003c/a\u003e\n\nThis repo was written and is maintained by the [Fullstack React](https://fullstackreact.com) team. In the book we cover many more projects like this. We walk through each line of code, explain why it's there and how it works.\n\nThis app is only one of several apps we have in the book. If you're looking to learn React, there's no faster way than by spending a few hours with the Fullstack React book.\n\n\u003cdiv style=\"clear:both\"\u003e\u003c/div\u003e\n\n## License\n [MIT](/LICENSE)\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffullstackreact%2Fredux-modules","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffullstackreact%2Fredux-modules","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffullstackreact%2Fredux-modules/lists"}