infinitered / ignite-redux-persist

An Ignite CLI plugin for Redux Persist
9 stars 2 forks source link

How to use PersistGate in App.js after applying this plugin? #8

Open kumarpatel opened 6 years ago

kumarpatel commented 6 years ago

Generated boilerplate PizzaApp using ignite-cli v2.0.0

class App extends Component {
  render () {
    return (
      <Provider store={store}>
        <RootContainer />
      </Provider>
    )
  }
}

needs to become

 <PersistGate persistor={persistor}>
        <Provider store={store}>
            <RootContainer />
      </Provider>
 </PersistGate>

How do I get access to persistor here? Seems to be generated in Rehydration.js

Any help would be appreciated.

ryanlntn commented 6 years ago

Hey @kumarpatel.

I'd probably define it right below startup

const persistor = persistStore(store, null, startup)

Then update the calls to persistStore to use that persistor and add it to the exports. Then you can just import it from Rehydration.

If you're interested this would be a welcome PR! 😄

apparition47 commented 6 years ago

@ryanlntn Still not quite sure how to pass down the persistor. Would this work?

// Rehydration.js
const updateReducers = (store: Object) => {
  const reducerVersion = ReduxPersist.reducerVersion
  const startup = () => store.dispatch(StartupActions.startup())
  const persistor = persistStore(store, null, startup)

  // Check to ensure latest reducer version
  AsyncStorage.getItem('reducerVersion').then((localVersion) => {
    if (localVersion !== reducerVersion) {
      if (DebugConfig.useReactotron) {
        console.tron.display({
          name: 'PURGE',
          value: {
            'Old Version:': localVersion,
            'New Version:': reducerVersion
          },
          preview: 'Reducer Version Change Detected',
          important: true
        })
      }
      // Purge store
      AsyncStorage.setItem('reducerVersion', reducerVersion)
      persistor.purge()
    }
  }).catch(() => {
    AsyncStorage.setItem('reducerVersion', reducerVersion)
  })

  return persistor
}
// CreateStore.js
  // configure persistStore and check reducer version number
  let persistor
  if (ReduxPersist.active) {
    persistor = Rehydration.updateReducers(store)
  }

  // kick off root saga
  let sagasManager = sagaMiddleware.run(rootSaga)

  return {
    store,
    persistor,
    sagasManager,
    sagaMiddleware
  }
// App.js
// create our store
const { persistor, store } = createStore()

class App extends Component {
  render () {
    return (
      <Provider store={store}>
        <PersistGate
          persistor={persistor}>
          <App />
        </PersistGate>
      </Provider>
    )
  }
}
kumarpatel commented 6 years ago

@ryanlntn I tried your suggested solution as well. Still not sure how to pass down persistor object since AsyncStorage.getItem is a promise function.

ryanlntn commented 6 years ago

@apparition47 That looks like it should work and is more or less what I had in mind. Have you tried it out?

@kumarpatel Take a look at @apparition47's code above. You'll have to return the persistor outside of the promise which should be fine as it's the same instance.

kumarpatel commented 6 years ago

@ryanlntn Yup. tried out @apparition47 's code.

Changing ReduxPersist.reducerVersion doesn't seem to be purging.

kumarpatel commented 6 years ago

nvm. Just realized that this purges persisted data. i.e. not my redux state. I'll try to fire off a redux action to clear my redux state.

apparition47 commented 6 years ago

@ryanlntn It seems to work in my app from what I can see. Wasn't sure if there was a more graceful way to return the persistor though. If not, I can put this through as a PR if you'd like.

ryanlntn commented 6 years ago

@apparition47 I think you could move the persistor creation out into CreateStore.js and then pass it into updateReducers for the sake of purging. That would be a little clearer since updateReducers doesn't really imply it's going to return a persistor.

kumarpatel commented 6 years ago

just read redux-persist v5 docs a little more closely about purging state if reducerVersion doesn't match. Migrations is the suggested way. Which means, Rehydration is a file that I don't need anymore. I just get my persistor in CreateStore.js and pass it down to App.js.

I'm cool with having this issue closed. Thanks for your help.

HZSamir commented 6 years ago

This is all rather confusing. @apparition47 example code did not work for me. Could I trouble any one of you for a complete example? Thank you.

kumarpatel commented 6 years ago

@Unforgiven-wanda You don't need Rehydration file anymore

In CreateStore.js,

import { persistStore } from "redux-persist";
...

const persistor = persistStore(store);

// return your store and persistor
return { store, persistor };

in App.js (see official doc)

import createStore from "../Redux";
import { PersistGate } from 'redux-persist/integration/react'

//retrieve your store & persistor
const { store, persistor } = createStore();

// ... normal setup, create store and persistor, import components etc.

const App = () => {
  return (
    <Provider store={store}>
      <PersistGate loading={null} persistor={persistor}>
        <RootComponent />
      </PersistGate>
    </Provider>
  );
};

You can manually purge your store: persister.purge(). You'll just need to pass persistor object down as needed. Or using redux-persist migrations to add data migration logic for old state -> new state. This migration can be as complicated as migrating every piece of data from old state to new state or as simple as purging old state and starting from scratch for new state. All depends on your business need.

Hopefully this helps.

yudistiraashadi commented 6 years ago

Hey, for everyone who wants to use the code from @kumarpatel above, you also need to change Redux/index.js to

export default () => {
  ... 

  let { store, persistor, sagasManager, sagaMiddleware } = configureStore(
    finalReducers,
    rootSaga
  );
  ...

  return { store, persistor };
};
oktalk commented 6 years ago

So, I've followed all of the examples here (thank you for that by the way) and I can see in Reactotron that I have an action of type:persist/REHYDRATE and persist/PERSIST firing when the app loads, but my whitelisted Redux state is only loading it's initialState.

Is there some other magic that I'm missing here? Do I need to call a special action for loading state into redux-persist?

jasan-s commented 5 years ago

@kumarpatel you mentioned don't need the Rehydration file. where/when would i exactly use persister.purge() to always grab the correct version of reducer.

jasan-s commented 5 years ago

@ryanlntn Still not quite sure how to pass down the persistor. Would this work?

// Rehydration.js
const updateReducers = (store: Object) => {
  const reducerVersion = ReduxPersist.reducerVersion
  const startup = () => store.dispatch(StartupActions.startup())
  const persistor = persistStore(store, null, startup)

  // Check to ensure latest reducer version
  AsyncStorage.getItem('reducerVersion').then((localVersion) => {
    if (localVersion !== reducerVersion) {
      if (DebugConfig.useReactotron) {
        console.tron.display({
          name: 'PURGE',
          value: {
            'Old Version:': localVersion,
            'New Version:': reducerVersion
          },
          preview: 'Reducer Version Change Detected',
          important: true
        })
      }
      // Purge store
      AsyncStorage.setItem('reducerVersion', reducerVersion)
      persistor.purge()
    }
  }).catch(() => {
    AsyncStorage.setItem('reducerVersion', reducerVersion)
  })

  return persistor
}
// CreateStore.js
  // configure persistStore and check reducer version number
  let persistor
  if (ReduxPersist.active) {
    persistor = Rehydration.updateReducers(store)
  }

  // kick off root saga
  let sagasManager = sagaMiddleware.run(rootSaga)

  return {
    store,
    persistor,
    sagasManager,
    sagaMiddleware
  }
// App.js
// create our store
const { persistor, store } = createStore()

class App extends Component {
  render () {
    return (
      <Provider store={store}>
        <PersistGate
          persistor={persistor}>
          <App />
        </PersistGate>
      </Provider>
    )
  }
}

persistor = Rehydration.updateReducers(store) this is an async call so need to account for it. @apparition47 what did you end up doing?

Tushar13kohli commented 5 years ago

've followed all of the examples here (thank you for that by the way) and I can see in Reactotron that I have an action of type:persist/REHYDRATE and persist/PERSIST firing when the app loads, but my whitelisted Redux state is only loading it's initialState.

Is there some other magic that I'm missing here? Do I need to call a special action for loading state into redux-persist?

I am facing the same problem . Were you able to solve it ?