GithubHelp home page GithubHelp logo

redux-action-buffer's Introduction

Redux Action Buffer

A middleware for redux that buffers all actions into a queue until a breaker condition is met, at which point the queue is released (i.e. actions are triggered).

One potential use case for this is to buffer any actions that occur before you are finished initializing your app. For example in conjunction with redux-persist.

Usage

import createActionBuffer from 'redux-action-buffer'
let breaker = BREAKER_ACTION_TYPE
let actionBuffer = createActionBuffer(
  BREAKER_ACTION_TYPE,
  (err, data) => {
    // callback fired immediately after releasing the buffer
    // data: { results: [actionReturnValue], queue: [rawAction] }
  }
)

Redux Persist Example

In short:

createActionBuffer({ breaker: REHYDRATE, passthrough: [PERSIST] })

Full example:

import { REHYDRATE } from 'redux-persist'
import createActionBuffer from 'redux-action-buffer'
import { createStore, compose } from 'redux'

let enhancer = compose(
  autoRehydrate(),
  applyMiddleware(
    createActionBuffer(REHYDRATE) //make sure to apply this after redux-thunk et al.
  )
)

createStore(
  reducer,
  {},
  enhancer
)

Notes

Delaying actions can be tricky because many actions depend on having a return value, and buffering breaks that. To help catch this scenario the return value from all buffered actions is a string indicating the action has been buffered.

API

actionBuffer(options, callback)

  • options (string | function | object): Either a action type string that will break the buffer or a function that takes an action as the argument and returns true when the buffer should be broken. An object is interpreted as { breaker: (string | function), passthrough: (Array) } where breaker functions as before and passthrough is an array of actions not to buffer.
  • callback (function): A function that is invoked after the buffer is broken.

redux-action-buffer's People

Contributors

antwnis avatar brownbl1 avatar jeroenbourgois avatar jscinoz avatar karelbilek avatar klathmon avatar rt2zz avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

redux-action-buffer's Issues

Buffer not working

@rt2zz is the following correct? Because I still get the following by redux persist when the only action fired is the classic redux @@init!

 redux-persist/autoRehydrate: 1 actions were fired before rehydration completed. This can be a symptom of a race
      condition where the rehydrate action may overwrite the previously affected state. Consider running these actions
      after rehydration:
    
autoRehydrate.js:65 redux-persist/autoRehydrate: sub state for key `auth` modified, skipping autoRehydrate.
import { createStore, combineReducers, applyMiddleware } from 'redux';
import { composeWithDevTools } from 'redux-devtools-extension/developmentOnly';
import { routerMiddleware, routerReducer } from 'react-router-redux';
import thunkMiddleware from 'redux-thunk';
import promiseMiddleware from 'redux-promise';
import createLogger from 'redux-logger';
import { browserHistory } from 'react-router';

import { REHYDRATE } from 'redux-persist/constants'
import { persistStore, autoRehydrate } from 'redux-persist';
import createActionBuffer from 'redux-action-buffer';
import crosstabSync from 'redux-persist-crosstab';

import authReducer from './auth.reducer.js';

const reducers = {
	routing: routerReducer,
	auth: authReducer,
};
const finalReducer = combineReducers(reducers);

const loggerMiddleware = createLogger();
const finalMiddleware = applyMiddleware(
	routerMiddleware(browserHistory),
	thunkMiddleware,
	promiseMiddleware,
	createActionBuffer(REHYDRATE),
	loggerMiddleware,
);

const store = createStore(finalReducer, {}, composeWithDevTools(
	finalMiddleware,
	autoRehydrate({ log: true }),
));

export default store;

Trying to use redux-action-buffer with redux-persist

I am trying to use redux-persist with redux-action-buffer, but it doesn't seem to be working as described in the documentation.

My simple example is as follows:

import {applyMiddleware, createStore, compose} from 'redux';
import {persistStore, autoRehydrate} from 'redux-persist';
import createActionBuffer from 'redux-action-buffer';
import {REHYDRATE} from 'redux-persist/constants';

function reducer(state = {foo: ["bar"]}, action) {
  if (action.type === 'ADD_FOO') {
    return {
      foo: [...state.foo, action.item]
    }
  }
  return state;
}

const enhancer = compose(
  autoRehydrate(),
  applyMiddleware(
    createActionBuffer(REHYDRATE)
  )
);

const store = createStore(
  reducer,
  undefined,
  enhancer
);

persistStore(store);

store.dispatch({
  type: 'ADD_FOO',
  item: 'baz'
});

store.dispatch({
  type: 'ADD_FOO',
  item: 'hocus pocus'
});

setTimeout(() => {
  // the state is correct...
  console.log(store.getState());
  // but nothing in the localStorage!
  console.log(localStorage);
}, 1000);

According to redux-persist documentation and redux-action-buffer documentation, this should work. Yet it doesn't and nothing is saved to localstorage.

If I change the store.dispatch code to run inside the callback, as in

persistStore(store, undefinded, () => {
    store.dispatch(....

it seems to be working; but in that case, the redux-action-buffer is not doing what it should and it doesn't actually buffer anything.

I am beginning with Redux so I might be missing something. :)

Order of actions dispatched within promises in v1.1.0

I discovered some strange behaviour with the 1.1.0 release. When dispatching actions within promises the resulting order is no longer correct (or actions are missing). The problem seems to be caused by the use of setImmediate/setTimeout.

I tried to replicate this behaviour in the following test (works with 1.0.1 fails for 1.1.0):

import test from 'ava'
import { createStore, applyMiddleware } from 'redux'
import actionBuffer from '../index'

test('buffers async actions in correct order', t => {
    const actionHistory = []

    const store = createStore(
        (state, action) => {
            if (action.type.indexOf('@@') !== 0) actionHistory.push(action)
            return {}
        },
        null,
        applyMiddleware(actionBuffer('BREAKER'))
    )

    const action1 = {type: 'ACTION1'}
    const action2 = {type: 'ACTION2'}
    const breaker = {type: 'BREAKER'}

    store.dispatch(action1)

    return new Promise(resolve => {
        store.dispatch(breaker)
        store.dispatch(action2)
        resolve()
    }).then(() => {
        t.is(actionHistory[0], breaker)
        t.is(actionHistory[1], action1)
        t.is(actionHistory[2], action2)
    })
})

TypeScript complains about missing default export

In the docs you show the following:

import createActionBuffer from 'redux-action-buffer'

createActionBuffer is not a default export though (it is exported directly through module.exports), so TypeScript complains. Babel copes with it as it seems to be more permissive.

We could either introduce a transpiler, or mimic what Babel does with default exports currently:

Object.defineProperty(exports, "__esModule", {
  value: true
});

exports.default = createActionBuffer;

function createActionBuffer() {
  // ...
}

What do you think?

autoRehydrate

When using the enhancer like in the docs, the creation of my store fails. However if I omit the autoRehydrate it seems to work. Is it an error in the docs or am I doing something wrong?

Here is my full 'configureStore' file:

'use strict'

import { AsyncStorage } from 'react-native'
import { createStore, compose, applyMiddleware } from 'redux'
import rootReducer from '../reducers'
import thunk from 'redux-thunk'

import {REHYDRATE} from 'redux-persist/constants'
import createActionBuffer from 'redux-action-buffer'

import {persistStore, autoRehydrate} from 'redux-persist'

const enhancer = compose(
  // autoRehydrate,
  applyMiddleware(
    thunk,
    createActionBuffer(REHYDRATE) //make sure to apply this after redux-thunk et al.
  )
)

export const store = createStore(
  rootReducer,
  {},
  enhancer
)

persistStore(store, {storage: AsyncStorage}, () => {
  console.log(">>> RESTORED")
})

redux-action-buffer before thunk middleware

In your documentation, you suggest that the user place the middleware returned createActionBuffer after the thunk middleware. Your code does not actually necessitate this, and there are use cases where you may want to delay thunks before state is loaded: for example, if you need data from the stored state to make a network request.

Object doesn't support property or method 'includes' in IE

My application stopped running in IE when trying to implement this middleware.

Appears it uses the includes() method, which is not supported in IE: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes

Users needing to support IE should be polyfilling this.
FYI: for create-react-app users, a "import 'core-js/es7/array';" in your index.js should suffice as well.

Just leaving it here, unsure if this is something that should be fixed in the module or at least documented somewhere.

Unexpected behavior of buffer with nested dispatches

Hi. I've noticed that some of the actions are fired before releasing the queue in 1.0.1.

It happens here when the result of next is calculated.

  active = false
  var result = next(action)

The action is going deep to original dispatch and is dispatched but not returned.
After that, all Redux listeners are called, in my particular case they are callbacks from React-Redux.
Listeners cause some of my components to update and dispatch new actions.
These new actions are handled before the queue release because flag active has been already set to false.

What I expect in this case is that these actions should be pushed to the queue and released with it even if they came after breaking condition, am I right?

Version 1.1.0 and redux-loop

Have you experienced any issues when using redux-action-buffer 1.1.0 with redux-loop?

For some reason the actions using redux-loop never fire when we updated to 1.1.0

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.