michaelcontento / redux-storage

Persistence layer for redux with flexible backends
MIT License
675 stars 50 forks source link

State is not updating on load #154

Closed adambutler closed 7 years ago

adambutler commented 8 years ago

I am finding that my state is not being populated correctly when the REDUX_STORAGE_LOAD action is dispatched -

63053a8e-63d3-11e6-986d-cfee2bfc9158

I've ruled out a save occurring before load by whitelisting just one action.

My storage reducer is simply -

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

export default function storeageAwareReducer(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;
  }
}

My store setup is very standard and follows the example in the readme and I am using the redux-storage-engine-reactnativeasyncstorage engine -

import * as storage from 'redux-storage'
import createEngine from 'redux-storage-engine-reactnativeasyncstorage';
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import createLogger from 'redux-logger';
import { APP } from '../configs/index';
import api from 'CookAndCount/app/middleware/api';

import rootReducer from '../reducers/index';

// Wrap reducer for use with redux-storage
const reducer = storage.reducer(rootReducer);

const logger = createLogger();

// Create a storage engine for AsyncStorage
let storage_key = `cook-and-count-${APP.STORAGE_SUFFIX}`;

const engine = createEngine(storage_key);

// Create middleware - thunk and storage
const middleware = [thunk, api, logger, storage.createMiddleware(engine)];

// Create store with middleware applied
const store = createStore(rootReducer, applyMiddleware(...middleware));

// Load in previous app state
const load = storage.createLoader(engine);

load(store)

export default store;

When I listen to the promise I am getting the intended state and no errors -

load(store)
  .then((newState) => console.log('Loaded state:', newState))
  .catch(() => console.log('Failed to load previous state'));
adambutler commented 8 years ago

From the readme I was under the impression that the store would rehydrate itself based on the stored data especially given that by default this library saves everything why would it not restore everything.

My understanding is either completely wrong, in which I would hope that the readme can be updated to shed some light on this issue, or this is still an issue and I have found a way to work around it by implementing the LOAD action on each reducer -

import { COOKBOOKS_LOADED } from 'CookAndCount/app/actions/Cookbooks';
import { LOAD, SAVE } from 'redux-storage';

const initialState = {
  ids: [],
};

export default function reducer(state = initialState, action = {}) {
  switch (action.type) {

    case LOAD:
      return {
        ...state,
        ...action.payload.cookbooks,
        loaded: true,
      }

    case COOKBOOKS_LOADED:
      console.log(action);
      return {
        ...state,
        ids: action.payload.result.cookbooks,
      };

    default:
      return state;
  }
}
JesseObrien commented 8 years ago

I seem to be having the same issue, with basically the same code you have above initialising everything. Anyone have any insight?

HellerCommaA commented 8 years ago

Nearly identical issue. You guys get anywhere?

adambutler commented 8 years ago

I've ended up just implementing the LOAD action in all of the reducers (as per my last comment) to restore the data. I'm guessing that is how it is supposed to work but the documentation is a little unclear if that is indeed the case.

HellerCommaA commented 8 years ago

Right on, I'll check that out.

I can't seem to get my second store to sync back to the main store, despite it loading a valid (current) initial state. -- It's receiving non-initialState values, but not getting updates, if that makes sense.

Secondly, syncing two stores via localstorage may be out of scope for this lib. O_O

adambutler commented 8 years ago

@HellerCommaA Are you using react-native-router-flux by any chance?

HellerCommaA commented 8 years ago

Negative. I'm in the react Discord #redux @tech if you want to ping me there instead of blowing up a GH issue.

HellerCommaA commented 8 years ago

@adambutler i actually just flipped over to redux-persist with crosstabSync.

import { createStore, applyMiddleware, compose } from 'redux'
import combineReducer from './reducer'
import { persistStore, autoRehydrate } from 'redux-persist'
import crosstabSync from 'redux-persist-crosstab'
const finalCreateStore = compose(autoRehydrate())(createStore)
const store = finalCreateStore(combineReducer)

const persistor = persistStore(store, {})
crosstabSync(persistor)

export default store

and everything ran out of the box with no issues.

jaredramirez commented 7 years ago

Same issue here, anyone figure out other solutions?

HellerCommaA commented 7 years ago
import { createStore, applyMiddleware, compose } from 'redux'
import myReducer from './reducer'
import { persistStore, autoRehydrate } from 'redux-persist'
import crosstabSync from 'redux-persist-crosstab'
const finalCreateStore = compose(autoRehydrate(), window.devToolsExtension ? window.devToolsExtension() : f => f)(createStore)
const store = finalCreateStore(myReducer)

const persistor = persistStore(store, {debounce: 2})
crosstabSync(persistor)

export default store

is what I'm running for now. seems to be working. I'm able to push / pull state between two synced stores.

gijoehosaphat commented 7 years ago

I have seemingly run into a similar issue as well. What the state is on REDUX_STORAGE_SAVE is not what is being LOADed back in. I'd rather not switch to another storage solution, like redux-persist

michaelcontento commented 7 years ago

Sorry for the bad news but this package is no longer maintained. 😞

My focus has left the react / node ecosystem and I don't have to time to keep things up to date. But if you want to step in and become the new maintainer of redux-storage and all of it parts, just ping me! 😃

roby-rodriguez commented 7 years ago

A bit late to the party, I was dealing with (most likely) a similar problem. Have you tried using the reducer from the library? Something like:

import { combineReducers } from 'redux'
import { reducer as storageMergeReducer } from 'redux-storage'
import Login from "~/screens/Login"
import ...

const rootReducer = combineReducers({
    Login,
    ...
})

export default storageMergeReducer(rootReducer)

In my case this was necessary to merge the stored state on loading. Check the source.