Redux Resource
  • Home
  • Introduction
    • Motivation
    • Core Concepts
    • Similar Projects
    • Examples
  • Resources
    • Resource Reducers
    • Resource Objects
    • Meta
    • Lists
    • Modifying Resources
  • Requests
    • Request Objects
    • Keys
    • Names
    • Statuses
    • Request Actions
      • Updating Lists
      • Reading Resources
      • Updating Resources
      • Creating Resources
      • Deleting Resources
  • Other Guides
    • Usage With React
    • Tracking Request Statuses
    • Using Request Statuses
    • Custom Action Types
    • Migration Guides
  • Recipes
    • Forms
    • Canceling Requests
    • Unauthorized Responses
    • User Feedback
    • Related Resources
    • Caching
  • Ecosystem Extras
    • Redux Resource Action Creators
    • Redux Resource XHR
    • Redux Resource Prop Types
    • Redux Resource Plugins
      • HTTP Status Codes
      • Selection
      • Reset
      • Included Resources
  • FAQ
    • General
    • State Tree
    • Actions
    • Lists
  • API Reference
    • resourceReducer
    • getStatus
    • getResources
    • upsertResources
    • setResourceMeta
    • actionTypes
    • requestStatuses
Powered by GitBook
On this page
  • Using a Plugin
  • Writing a Plugin
  • Selecting Resources
  • Customizable Plugins
  • Best Practices
  1. Other Guides

Custom Action Types

PreviousUsing Request StatusesNextMigration Guides

Last updated 5 years ago

You can add support for additional action types to a using plugins.

The name 'plugins' may seem intimidating, but don't be worried. Plugins are reducers that you can reuse for any resource slice. If you know how to write a reducer, then you know how to write a plugin.

Using a Plugin

You define plugins for each resource type when you call . The second argument to that function is an options option, and within it you can pass plugins as an array:

import resourceReducer from 'redux-resource';
import somePlugin from './some-plugin';
import anotherPlugin from './another-plugin';

export default resourceReducer('books', {
  plugins: [somePlugin, anotherPlugin]
});

Writing a Plugin

A plugin is a function that with the following signature:

(resourceType, options) => reducerFunction

Where resourceType and options are the arguments that you passed to .

The return value, reducerFunction, is also a function. This returned function has the same signature as a Redux reducer:

(previousState, action) => newState

where state is the value of the state after running it through the built-in reducer and action is the action that was dispatched.

The simplest plugin then (which doesn't do anything), would look like this:

function myPlugin(resourceType, options) {
  return function(state, action) {
    return state;
  }
}

If you prefer using arrow functions, you might choose to write this like so:

const myPlugin = (resourceType, option) => (state, action) => state;

This plugin isn't very exciting, so let's look at more realistic examples.

Selecting Resources

Let's build a plugin that lets a user select resources. The code for this plugin looks like this:

import { setResourceMeta } from 'redux-resource';
import myActionTypes from './my-action-types';

export default function(resourceType, options) {
  return function(state, action) {
    // Ignore actions that were dispatched for another resource type
    if (action.resourceType !== resourceType) {
      return state;
    }

    if (action.type === myActionTypes.SELECT_RESOURCES) {
      return {
        ...state,
        meta: setResourceMeta({
          resources: action.resources,
          meta: state.meta,
          newMeta: {
            selected: true
          },
          initialResourceMeta: options.initialResourceMeta
        })
      };
    } else if (action.type === myActionTypes.UNSELECT_RESOURCES) {
      return {
        ...state,
        meta: setResourceMeta({
          resources: action.resources,
          meta: state.meta,
          newMeta: {
            selected: false
          },
          initialResourceMeta: options.initialResourceMeta
        })
      };
    } else {
      return state;
    }
  }
}

You would then use this plugin like so:

import { createStore, combineReducers } from 'redux';
import { resourceReducer } from 'redux-resource';
import selectResources from './plugins/select-resources';

let store = createStore(
  combineReducers({
    books: resourceReducer('books', {
      plugins: [selectResources]
    }),
  })
);

Customizable Plugins

You can write plugins that can be customized per-slice by taking advantage of the fact that the resourceReducer's options are passed into plugins. For instance, if you had a plugin like the following:

export default function customizablePlugin(resourceType, options) {
  return function(state, action) {
    if (options.useSpecialBehavior) {
      // Perform a computation
    } else {
      // Do some other computation here
    }
  };
}

then you could trigger the special behavior by passing useSpecialBehavior: true as an option to resourceReducer:

import resourceReducer from 'redux-resource';
import customizablePlugin from './customizable-plugin';

export default resourceReducer('books', {
  plugins: [customizablePlugin],
  useSpecialBehavior: true
});

If this API isn't to your liking, then you can also just wrap the plugin itself in a function, like so:

export default function(pluginOptions) {
  return function customizablePlugin(resourceType, options) {
    return function(state, action) {
      if (pluginOptions.useSpecialBehavior) {
        // Perform a computation
      } else {
        // Do some other computation here
      }
    };
  };
}

which would be used in the following way:

import resourceReducer from 'redux-resource';
import customizablePlugin from './customizable-plugin';

export default resourceReducer('books', {
  plugins: [
    customizablePlugin({ useSpecialBehavior: true})
  ]
});

You may dislike this approach due to the tripley-nested functions. That's fine, because either way works. Use the version that makes the most sense to you.

Best Practices

Because plugins are so similar to reducers, you can use a switch statement and support multiple action types within each plugin. This is usually a good thing, but be mindful of keeping each plugin limited to a single responsibility.

For example, in the above example of a plugin for selecting resources, it supports two Action types – one for selection, and one for deselection. This plugin encapsulates that one responsibility, and it isn't responsible for any other Action types.

We recommend having a plugin for each distinct responsibility.

resourceReducer
resourceReducer
resourceReducer