Git Product home page Git Product logo

redux-storage's Introduction

build dependencies devDependencies

license npm version npm downloads Code Climate

Save and load the Redux state with ease.

Moved to the react-stack organisation

My focus has left the node / react ecosystem and this module has got a new home over at react-stack!

Features

  • Flexible storage engines
  • Flexible state merger functions
  • Storage engines can be async
  • Load and save actions that can be observed
    • SAVE: { type: 'REDUX_STORAGE_SAVE', payload: /* state tree */ }
    • LOAD: { type: 'REDUX_STORAGE_LOAD', payload: /* state tree */ }
  • Various engine decorators
  • Black- and whitelist actions from issuing a save operation

Installation

npm install --save redux-storage

And you need to install at least one redux-storage-engine, as redux-storage is only the "management core".

Usage

import * as storage from 'redux-storage'

// Import redux and all your reducers as usual
import { createStore, applyMiddleware, combineReducers } from 'redux';
import * as reducers from './reducers';

// We need to wrap the base reducer, as this is the place where the loaded
// state will be injected.
//
// Note: The reducer does nothing special! It just listens for the LOAD
//       action and merge in the provided state :)
// Note: A custom merger function can be passed as second argument
const reducer = storage.reducer(combineReducers(reducers));

// Now it's time to decide which storage engine should be used
//
// Note: The arguments to `createEngine` are different for every engine!
import createEngine from 'redux-storage-engine-localstorage';
const engine = createEngine('my-save-key');

// And with the engine we can create our middleware function. The middleware
// is responsible for calling `engine.save` with the current state afer
// every dispatched action.
//
// Note: You can provide a list of action types as second argument, those
//       actions will be filtered and WON'T trigger calls to `engine.save`!
const middleware = storage.createMiddleware(engine);

// As everything is prepared, we can go ahead and combine all parts as usual
const createStoreWithMiddleware = applyMiddleware(middleware)(createStore);
const store = createStoreWithMiddleware(reducer);

// At this stage the whole system is in place and every action will trigger
// a save operation.
//
// BUT (!) an existing old state HAS NOT been restored yet! It's up to you to
// decide when this should happen. Most of the times you can/should do this
// right after the store object has been created.

// To load the previous state we create a loader function with our prepared
// engine. The result is a function that can be used on any store object you
// have at hand :)
const load = storage.createLoader(engine);
load(store);

// Notice that our load function will return a promise that can also be used
// to respond to the restore event.
load(store)
    .then((newState) => console.log('Loaded state:', newState))
    .catch(() => console.log('Failed to load previous state'));

Details

Engines, Decorators & Mergers

They all are published as own packages on npm. But as a convention all engines share the keyword redux-storage-engine, decorators can be found with redux-storage-decorator and mergers with redux-storage-merger. So it's pretty trivial to find all the additions to redux-storage you need ๐Ÿ˜„

Actions

redux-storage will trigger actions after every load or save operation from the underlying engine.

You can use this, for example, to display a loading screen until the old state has been restored like this:

import { LOAD, SAVE } from 'redux-storage';

function storageAwareReducer(state = { loaded: false }, action) {
    switch (action.type) {
        case LOAD:
            return { ...state, loaded: true };

        case SAVE:
            console.log('Something has changed and written to disk!');

        default:
            return state;
    }
}

Middleware

If you pass an array of action types as second argument to createMiddleware, those will be added to a internal blacklist and won't trigger calls to engine.save.

import { createMiddleware } from 'redux-storage'

import { APP_START } from './constants';

const middleware = createMiddleware(engine, [ APP_START ]);

If you want to whitelist all actions that are allowed to issue a engine.save, just specify them as third argument.

import { createMiddleware } from 'redux-storage'

import { SHOULD_SAVE } from './constants';

const middleware = createMiddleware(engine, [], [ SHOULD_SAVE ]);

License

The MIT License (MIT)

Copyright (c) 2015 Michael Contento

Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

redux-storage's People

Contributors

benjamingr avatar cef62 avatar dbachrach avatar friegger avatar gasperz avatar greenkeeperio-bot avatar hjagodzinski avatar jdlehman avatar mathieudutour avatar mattkrick avatar michaelcontento avatar miracle2k avatar romanenko avatar skevy avatar slightlytyler avatar uxter avatar xanderwebs 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  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  avatar  avatar  avatar  avatar

redux-storage's Issues

Splitting the decorators from the core

Right now, when using this package without immutable, it will still require immutablejs which is quite big.

Each decorators should be required separately or be in its own package.

Importing constants not working

In the README's "Actions" example:

import { LOAD, SAVE } from 'redux-storage';

Importing the constants in this way doesn't work as they are exposed as properties of the default export object, rather than as named exports.

I've gotten around this with something like:

import storage from 'redux-storage';
const { LOAD, SAVE } = storage;

We could either:

  1. Update the README example, or
  2. Change the way the constants are exported

What do you think?

failing to load initial state, but actually is loading initial state, but then causing other issues

For whatever reasons, the catch statement of the promise returned by load is being called, but the previous state is in fact loading. That's not the real issue that's causing me problems though--Redux's connect mapStateToProps functions aren't being called again when the state changes. I've pintpointed this as a Redux Storage issue because when I remove the load call of Redux Storage, everything works.

So my thinking is that it's "failing" not so much in that the loading of previous state fails, but failing in some other regards with how it interfaces with the rest of Redux. What are the common reasons the promise's catch would be triggered?

Race condition on Android with React Native

Using the example code you provided, I get the following console log on iOS, where the app works just fine.

Running application "MyApp" with appParams: {"rootTag":1,"initialProps":{}}. __DEV__ === true, development-level warning are ON, performance optimizations are OFF
action REDUX_STORAGE_LOAD @ 16:00:00.589
    prev state Object {initialLoad: false, currentUser: Object, entities: Object}
    action Object {type: "REDUX_STORAGE_LOAD", payload: Object}
    next state Object {initialLoad: true, currentUser: Object, entities: Object}
Loaded state: Object {}

But on Android, the storage loads immediately before the react native app starts up, causing some issues with waiting for the state to be loaded from disk. Here's the Android log.

action REDUX_STORAGE_LOAD @ 16:00:00.500
    prev state Object {initialLoad: false, currentUser: Object, entities: Object}
    action Object {type: "REDUX_STORAGE_LOAD", payload: Object}
    next state Object {initialLoad: true, currentUser: Object, entities: Object}
Loaded state: Object {}
Running application "MyApp" with appParams: {"initialProps":{},"rootTag":1}. __DEV__ === true, development-level warning are ON, performance optimizations are OFF

Workaround

Rather than relying on componentWillReceiveProps to check if store has loaded, I'll make that check in both my componentDidMount and componentWillReceiveProps methods.

ReactNative - JS load error

I have installed redux-storage using npm install and also made sure to rebuilt app etc.

When I have the following line in my redux store, the JS fails to load:

import createEngine from 'redux-storage/engines/reactNativeAsyncStorage';

I tried emulator and physical device, and both give error: 'Unable to download JS bundle.Did you forget to start the dev server...'

If I take out that line and reload js, the app works normally. This is with the folliowing dependencies:

  "dependencies": {
    "immutable": "=3.7.6",
    "react": "=0.14.3",
    "react-native": "=0.16.0",
    "react-native-radio-buttons": "^0.8.0",
    "react-redux": "=3.1.2",
    "redux": "=3.0.5",
    "redux-storage": "^1.4.3",
    "underscore": "^1.8.3"
  },

Any suggestions of what might be causing this ?

Data in Local/Session storage resets to initialState on refresh

I've tried redux-storage-engine-sessionstorage and redux-storage-engine-localstorage, and at first I see data saving correctly. Then when I refresh the page, all of that data is gone, and the data in storage is everything that is set as initialState in my reducers.

Anyone seen this before?

import createEngine from 'redux-storage-engine-sessionstorage';
import immutablejs from 'redux-storage-decorator-immutablejs';
import merger from 'redux-storage-merger-immutablejs';

let engine = createEngine('enjoymint');
engine = immutablejs(engine, [
  ['UserRed'],
  ['routing'],
  ['ErrorsRed'],
  ['MenuRed'],
  ['ModalsRed'],
  ['OrdersRed'],
  ['ProfileRed'],
  ['VendorRed']
]);

const finalReducers = storage.reducer(combineReducers(Object.assign({}, reducers, {
  routing: immutableRoutingReducer
})), merger);

const engineMiddleware = storage.createMiddleware(engine, [
  Constants.modals.OPEN_LOGIN_MODAL,
  Constants.modals.TOGGLE_ACCOUNT_DETAILS_MODAL,
  Constants.modals.TOGGLE_CC_MODAL,
  Constants.modals.TOGGLE_BILLING_MODAL,
]);

const routingMiddleware = routerMiddleware(createHistory);

const finalCreateStore = compose(
  applyMiddleware(thunk /*,logger*/, engineMiddleware, routingMiddleware),
  window.devToolsExtension ? window.devToolsExtension() : f => f
)(createStore);

const store = finalCreateStore(finalReducers);

const load = storage.createLoader(engine);
load(store)
  .then((newState) => console.log('Loaded state:', newState))
  .catch(() => console.log('Failed to load previous state'));

undefined: SecurityError

Getting following errors, possibly due local storage not being available in Safari private mode.

undefined: SecurityError: DOM Exception 18: An attempt was made to break through the security policy of the user agent.
QuotaExceededError: DOM Exception 22

Alt text

Maybe worth implementing extra check if localstorage is not available?

How to configure with fully immutable store?

Hi. I was trying to update from version 2.2 to 4.0 but ended up having lots of troubles. My store is fully immutable and I realise I need to at least import immutable decorators. Despite doing that and some other tricks I wasn't able to load store properly but got several errors. It would be really useful to see a working minimal example with all the relevant stuff or some improved documentation related to usage with immutable store.

Thanks for the nice library.

Blacklist based on keys instead of actions

It is convenient to blacklist based on state keys instead of actions.
For example, is it possible to tell redux-storage to not store router into localStorage when the global state looks like below?

state: {
  router: '...',
  currentUser: '...',
}

I am trying to make redux-storage not save router into localStorage. Doing so prevents the user from navigating the app by changing the url in his address bar.

Array default values

Hi! I have a test reducer:
myReducer = (state = { arr: [1, 2, 3] }, action) => action.type == 'TEST' ? { arr: [5] } : state
It's save to store correctly after dispatch: { arr: 5 }
But after load it's has a value { arr: [5, 2, 3] }.
Lo-dash _.merge problem.

Handling multiple users

Was looking to use this for a product with user accounts (not saving anything confidential), but I am thinking it is not suitable due to you defining the engine key and to load existing state at the application initialisation. If you have multiple users logging into the same machine you will not be able to load the correct data after they have logged in.

Or do you have suggestions on how to handle this scenario?

Versioned storage with migrations

Hi,

I am just curious if you thought about store migrations? What if we change structure? I think it should be responsibility of every reducer reviver.

storage is not defined

hi there,

I am relativly new to react native AND redux, sadly. But I want to master this and I wanted to implement your redux-storage.

As I want to implement this, I do not understand where storage comes from. You don't import it at the top.

So I end up with an storage is not defined error.

I defined my Reducer like this:

const Reducer = createReducer([], (state, action) => {
    switch (action.type) {

        case ActionTypes.addAthlete:

...
const configureStore = function configureStore(initialState) {
    return createStore(Reducer, initialState);
};
module.exports = {
    configureStore: configureStore,
    Actions: Actions
};

Can you help me? :) Thanks in advance!

Performance

Thanks for this useful lib. Since this library stores the whole state tree into one key-value pair, the performance will decrease greatly if we put too much data into the state tree. So what's the best approach to improve the performance when using too much data?

How can I clear the saved state?

This is an awesome solution for me, thanks!

I am using this with react-native and I'm wondering how to clear the state so i can start fresh if i mess something up in the state tree

blacklist doesn't work

I used the following code to exclude those actions. The strange thing is: TAB_CHANGE, SEGMENT_CHANGE don't trigger SAVE action, but DOWNLOAD_UPDATE action still triggers SAVE action. The difference between them is: DOWNLOAD_UPDATE action is very frequent.

const middleware = storage.createMiddleware(engine, [
  actionTypes.TAB_CHANGE, 
  actionTypes.DOWNLOAD_UPDATE,
  actionTypes.SEGMENT_CHANGE])

Prevent App from rendering until redux is loaded

Hi,

Occasionally my app crashes during startup. it is quite hard to debug this. My best guess is that the redux state was not fully loaded by the time the app begins to render. Reading the redux state during boot is quite important since it will define if the user already registered or not in the app

I was reading the F8 App and I came acros this code (below) Is possible to leverage same idea to prevent the app to render until redux is fully loaded?


  class Root extends React.Component {
    constructor() {
      super();
      this.state = {
        isLoading: true,
        store: configureStore(() => this.setState({isLoading: false})),
      };
    }
    render() {
      if (this.state.isLoading) {
        return null;
      }
      return (
        <Provider store={this.state.store}>
          <F8App />
        </Provider>
      );
    }
  }

Source:
https://github.com/fbsamples/f8app/blob/b5df451259897d1838933f01ad4596784325c2ad/js/setup.js#L61

Should the LOAD event be scoped to the reducer somehow?

When listening for the LOAD event, I'm given the entire state tree (as expected, I'm sure). My question is: should I be scoped to my current reducer somehow? In order for me to manipulate the state when loaded, I'd need to reach deep into the state tree, knowing all the paths of combineReducers above me.

I'm wondering if manipulating the state tree on LOAD is maybe an unsupported or discouraged use case. What I'm trying to do is wrap certain parts of the state tree in custom model classes, which can't be persisted and retrieved wrapped in their model. Is there a different recommended approach to achieve this?

Example state tree:

{
    auth: {
        user: new User({ id: 123, name: 'Sean' })
    }
}

This gets saved as:

{
    auth: {
        user: { id: 123, name: 'Sean' }
    }
}

So in my auth reducer, I want something like:

    [LOAD]: (state, action) => {
        return {
            ...state,
            user: new User(action.payload.user)
        };
    }

Or better yet:

    [LOAD]: (state, action) => {
        return {
            ...state,
            user: new User(state.user)
        };
    }

But instead, I must:

    [LOAD]: (state, action) => {
        return {
            ...state,
            user: new User(action.payload.auth.user)
        };
    }

Any knowing about the auth scoping is the part I don't like here.

Does that question make sense? Is there a different recommended approach to something like this?

Thanks!

Define engine key at `load()` time rather than `createEngine()`?

I'm running into a situation where I need to define the engine's save key after creating the redux store. I have a web app which serves different content for different 'shortcodes', i.e. example.com/<shortcode>, and I'm persisting only shortcode-specific state slices via redux-storage. In order to prevent different shortcodes' persistent state from conflicting, I'd like to use a different engine key for each shortcode.

For example, if I have /shortcodeA and /shortcodeB, and each shortcode has its own unique state.widgets slice, I want to be able to load & save shortcodeA's state.widgets using an engine key 'shortcodeA' so it doesn't conflict with shortcodeB's state under a 'shortcodeB' engine key.

Is this something that could be supported by redux-storage? Maybe the API could look something like

const load = storage.createLoader(engine);
// ...
load({
  key: 'my-save-key',
  // ... more engine options
}, store);

I'm going to play around with a few options and make a PR; anyone have any thoughts on how this should work?

Custom revivers for immutable js

Current solution works well only with immutable map or list, but there are more types. Especially immutable Record is pretty useful. I think I can workaround reviving initial state, just by loading manually stored state, and pass it as JSON. Check https://github.com/este/este/blob/master/src/common/todos/reducer.js#L19

But for LOAD action, I have no idea how to solve it. I will not use it for now, but I am curious If you have any idea how to deal with immutable custom types.

Combining engines

I've written a custom engine that I only want to use for a few keys in my state. The rest of them, I'd like to use redux-storage-engine-localstorage for. I assumed from the naming that this is what redux-storage-merger-immutablejs was for, but that doesn't appear to be the case.

My attempted approach:

import filter from 'redux-storage-decorator-filter';
import merge from 'redux-storage-merger-immutablejs';
import localStorageEngine from 'redux-storage-engine-localstorage';

const SPECIAL_FIELDS = [
  ['nested', 'key']
];

export default (key) => merge(
  filter(myEngine, SPECIAL_FIELDS),
  filter(localStorageEngine(key), null, SPECIAL_FIELDS)
);

So what should I be doing here?

ImmutableJS Still required

looks like immutablejs is still required for me, using 3.0.1. Based on commit history and the build/ folder installed via npm, it looks as though maybe a new version was not published to npm after updating source.

Merge() from lodash causes warnings in Immutable.js

I'm using Immutable decorator to load state data with localStorage engine. But on initial load I get a bunch of warnings from Immutable library:

iterable.length has been deprecated, use iterable.size or iterable.count(). This warning will become a silent error in a future version. Error
    at src_Map__Map.Object.defineProperty.get (webpack:///./~/immutable/dist/immutable.js?:4632:21)
    at pathKey (webpack:///./~/lodash/index.js?:2452:51)
    at isArrayLike (webpack:///./~/lodash/index.js?:4075:40)
    at baseMergeDeep (webpack:///./~/lodash/index.js?:2416:13)
    at eval (webpack:///./~/lodash/index.js?:2366:11)
    at arrayEach (webpack:///./~/lodash/index.js?:1289:13)
    at baseMerge (webpack:///./~/lodash/index.js?:2358:7)
    at eval (webpack:///./~/lodash/index.js?:3024:13)
    at eval (webpack:///./~/lodash/index.js?:8152:31)
    at exports.default (webpack:///./~/redux-storage/lib/reducer.js?:13:76)
immutable.js:4637 iterable.length has been deprecated, use iterable.size or iterable.count(). This warning will become a silent error in a future version. Error
    at src_Map__Map.Object.defineProperty.get (webpack:///./~/immutable/dist/immutable.js?:4632:21)
    at isTypedArray (webpack:///./~/lodash/index.js?:8998:51)
    at baseMergeDeep (webpack:///./~/lodash/index.js?:2416:60)
    at eval (webpack:///./~/lodash/index.js?:2366:11)
    at arrayEach (webpack:///./~/lodash/index.js?:1289:13)
    at baseMerge (webpack:///./~/lodash/index.js?:2358:7)
    at eval (webpack:///./~/lodash/index.js?:3024:13)
    at eval (webpack:///./~/lodash/index.js?:8152:31)
    at exports.default (webpack:///./~/redux-storage/lib/reducer.js?:13:76)
    at dispatch (webpack:///./~/redux/lib/createStore.js?:120:22)
immutable.js:4637 iterable.length has been deprecated, use iterable.size or iterable.count(). This warning will become a silent error in a future version. Error
    at src_Map__Map.Object.defineProperty.get (webpack:///./~/immutable/dist/immutable.js?:4632:21)
    at pathKey (webpack:///./~/lodash/index.js?:2452:51)
    at isArrayLike (webpack:///./~/lodash/index.js?:4075:40)
    at isArguments (webpack:///./~/lodash/index.js?:8469:37)
    at isPlainObject (webpack:///./~/lodash/index.js?:8924:77)
    at baseMergeDeep (webpack:///./~/lodash/index.js?:2421:18)
    at eval (webpack:///./~/lodash/index.js?:2366:11)
    at arrayEach (webpack:///./~/lodash/index.js?:1289:13)
    at baseMerge (webpack:///./~/lodash/index.js?:2358:7)

I guess, this is happening, because merge() function on lodash is used https://github.com/michaelcontento/redux-storage/blob/master/src/reducer.js#L8 when LOAD action being handled and it uses .length somehow.

What we can do with it?

Actions whitelist instead of blacklist

Whitelist instead of black list would make more sense. Generally we need to save only some actions.

Btw, this is well designed piece of library, thank you.

Uncaught (in promise) TypeError: store.dispatch is not a function createLoader.js:12

I just started to use it

import thunk from 'redux-thunk'
import * as storage from 'redux-storage'
import createEngine from 'redux-storage-engine-localstorage'

let storageMiddleware = storage.createMiddleware(engine)
let middleware = applyMiddleware(storageMiddleware, thunk)

const appReducer = storage.reducer(combineReducer({...}))

const store = middleware(createStore)(appReducer, {})

const load = storage.createLoader(engine)
load(storage).then(() => console.log('[storage] loaded'))

lazy load certain state

I have some arrays in my state that I don't need at app start right away. I'd rather load them when I first need to display them. Does redux-storage support that?

Why SAVE action dispatched with state not processed with engine?

I was playing with redux-storage-decorator-filter and noticed that SAVE action comes with untouched state. I supposed to catch the action with the filtered state.

I imagine all this flow like that:
image

I mean I think the SAVE action should be dispatched with state processed with decorators.

But with the current architecture it's hard to catch state between decorators and engine. The easiest way is to catch it right from engine.

const dispatchSave = (state = getState()) => dispatch(actionSave);
engine.save(saveState).then(dispatchSave).catch(swallow);

blacklist doesn't work

I used the following code to exclude those actions. The strange thing is: TAB_CHANGE, SEGMENT_CHANGE don't trigger SAVE action, but DOWNLOAD_UPDATE action still triggers SAVE action. The difference between them is: DOWNLOAD_UPDATE action is very frequent.

const middleware = storage.createMiddleware(engine, [actionTypes.TAB_CHANGE, actionTypes.DOWNLOAD_UPDATE, actionTypes.SEGMENT_CHANGE])

setTimeout around engine.save

We are currently using redux-storage and are experiencing that it slows down our app quite significantly due to many writes (debouncing didn't help in our case). As a small experiment we put a setTimeout(.., 1000) around the engine.save() command because we only want to save stuff as soon as there is no UI thread doing anything. And lo and behold, that surely sped things up quite a bit.

Would it be possible to have this as a feature and if not, are there complications?

Cheers,

Danny

3.0.1 to 4.0.0 with ImmutableJS, ReactNative

redux-storage doesnt like something about immutablejs objects when going from 3.0.1 to 4.0.0.
The following are with no code changes other than the version of reduxt-storage:

Loaded state appears the same on both versions like:
screen shot 2016-03-31 at 13 26 55

Although, once this state is merged to the redux store state, on 3.0.1 it looks like this:

screen shot 2016-03-31 at 13 26 42

Where on 4.0.0 it looks like this:

screen shot 2016-03-31 at 13 29 00

Also, 4.0.0 is triggering a warning once it tries to load state:

iterable.length has been deprecated, use iterable.size or iterable.count(). This warning will become a silent error in a future version. Error
    at Map.Object.defineProperty.get (http://localhost:8081/index.ios.bundle?platform=ios&dev=true:7922:7)
    at http://localhost:8081/index.ios.bundle?platform=ios&dev=true:85727:37
    at isArrayLike (http://localhost:8081/index.ios.bundle?platform=ios&dev=true:85846:30)
    at isArrayLikeObject (http://localhost:8081/index.ios.bundle?platform=ios&dev=true:85873:29)
    at isArguments (http://localhost:8081/index.ios.bundle?platform=ios&dev=true:85792:8)
    at indexKeys (http://localhost:8081/index.ios.bundle?platform=ios&dev=true:85754:36)
    at keysIn (http://localhost:8081/index.ios.bundle?platform=ios&dev=true:86032:9)
    at baseMerge (http://localhost:8081/index.ios.bundle?platform=ios&dev=true:86211:1)
    at http://localhost:8081/index.ios.bundle?platform=ios&dev=true:86768:1
    at http://localhost:8081/index.ios.bundle?platform=ios&dev=true:86404:1
index.js:128  action REDUX_STORAGE_LOAD @ 00:38:43.252

Blacklist and whitelist not working

I struggle making whitelist and blacklist working.

I understand the arrays passed to storage.createEngine should be objects with a type attribute. However, when I pass this like so:

const middleware = storage.createMiddleware(engine, [], [{type: "MY_ONLY_ACTION_TO_BE_SAVED"}]

nothing happens when I dispatch an action with that type.

If I don't pass anything, it saves the full state tree to the key I've provided to the engine I'm using. I currently use redux-storage-engine-localstorage.

Any idea why?

Tracking down instigators of SAVE

Love this package! :)

I'm using redux-storage-decorator-filter to restrict the save calls to a specific part of the state. I also just started using redux-sagas, so I put the three EFFECT_* actions into the storage blacklist, and they both work together beautifully.
However, I'm getting an extra REDUX_STORAGE_SAVE action which I have no clue why it's being dispatched, and there is no information I can see to help me figure it out. How do I track down the part of the code that caused the save operation to happen ... ?

Thanks !
-Guy

Reversed filter

A blacklist for keys would be useful, for components that save too much and non-serializable data

Persisting an Array within an Immutable map

I cannot understand what is wrong on my code and I get the following behaviour.

I have the following reducer:

import { Map } from 'immutable';
const initialState = Map();
export function stopwatch(state = initialState, action) {
  switch (action.type) {
    case STOPWATCH_UPDATE:
      return state.set('state', action.state);
    default:
      return state;
  }
}

And the following code creating a state:

 state = new Map({started: moment().unix(), active:true, entries: [0]});
 this.props.updateStopwatchState(state);

The started and active values are persisted as expected. The entries array though is not changing.
This is the code that is editing the entries:

      let timeActive = moment().unix() - state.get('started');
      let newEntries = state.get('entries');
      newEntries.push(timeActive);
      this.props.updateStopwatchState(
        new Map({started: null, active:false, entries: newEntries})
      );

If I take out the load function:

  load(store)
      .then((newState) => {
        console.log('Loaded state:', newState);
      })
      .catch(() => console.log('Failed to load previous state'));

the code works as expected.

Also, if I replace the entries array with a simple integer as seen bellow, it is persisted correct. So, I believe redux-storage doesn't like something about the array being in an immutable map ?

      let timeActive = moment().unix() - state.get('started');
      let currentTotal = state.get('total') + timeActive;
      this.props.updateStopwatchState(
        new Map({started: null, active:false, total: currentTotal})
      );

++++++ Extra info +++++

React native 0.19,

    "react-redux": "=4.4.0",
    "redux": "=3.3.1",
    "redux-storage": "=3.0.0",
    "redux-storage-decorator-filter": "=1.0.0",
    "redux-storage-engine-reactnativeasyncstorage": "=1.0.0",
    "redux-thunk": "=1.0.3"

This is how I create the store, and pass it to provider:

export default function configureStore() {
  const load = storage.createLoader(engine);

  let store = createStore(
    rootReducer,
    initialState,
    applyMiddleware(...middlewares)
  );

  load(store)
      .then((newState) => {
        console.log('Loaded state:', newState);
      })
      .catch(() => console.log('Failed to load previous state'));

  return store;
}

index.ios.js :

const store = configureStore();
let App = React.createClass({
  render: function() {
    return (
      <Provider store={store}>
       <AppContainer />
      </Provider>
    );
  }
});

Lodash as dependency

Error: Cannot find module 'lodash' from '/Users/e/dev/yard/frontend/node_modules/redux-storage/lib'

And do you really need entire lodash? You can include each functions separately, import { merge } from 'lodash'.

Reloading causes "Warning: You cannot PUSH the same path using hash history" with react-router-redux

This is a bug that arises from using popular packages together. I'm posting the bug here, and hoping you can cooperate with the involved parties.

If a user reloads an app that uses redux-storage & redux-storage-engine-localstorage & react-router & react-router-redux then the app will eventually complain with the error Warning: You cannot PUSH the same path using hash history.

Cause: React-storage triggers react-router-redux's enhanced react-router history, since it's causing a change in state. This in turns causes a history.push(...) to the restored URL, which is the same since it's a reload of the same page, thus causing the warning.

This issue doesn't seem to be directly addressed in the other projects since it's caused by using this plugin which automatically loads router state. Note that loading the state before enhanced router will avoid this bug, but then redux-storage fails to restore previous state on the second reload.

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.