persistStore.js.flow 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // @flow
  2. import type {
  3. Persistor,
  4. PersistConfig,
  5. PersistorOptions,
  6. PersistorState,
  7. MigrationManifest,
  8. RehydrateAction,
  9. RehydrateErrorType,
  10. } from './types'
  11. import { createStore } from 'redux'
  12. import { FLUSH, PAUSE, PERSIST, PURGE, REGISTER, REHYDRATE } from './constants'
  13. type PendingRehydrate = [Object, RehydrateErrorType, PersistConfig]
  14. type Persist = <R>(PersistConfig, MigrationManifest) => R => R
  15. type CreatePersistor = Object => void
  16. type BoostrappedCb = () => any
  17. const initialState: PersistorState = {
  18. registry: [],
  19. bootstrapped: false,
  20. }
  21. const persistorReducer = (state = initialState, action) => {
  22. switch (action.type) {
  23. case REGISTER:
  24. return { ...state, registry: [...state.registry, action.key] }
  25. case REHYDRATE:
  26. let firstIndex = state.registry.indexOf(action.key)
  27. let registry = [...state.registry]
  28. registry.splice(firstIndex, 1)
  29. return { ...state, registry, bootstrapped: registry.length === 0 }
  30. default:
  31. return state
  32. }
  33. }
  34. export default function persistStore(
  35. store: Object,
  36. options?: ?PersistorOptions,
  37. cb?: BoostrappedCb
  38. ): Persistor {
  39. // help catch incorrect usage of passing PersistConfig in as PersistorOptions
  40. if (process.env.NODE_ENV !== 'production') {
  41. let optionsToTest: Object = options || {}
  42. let bannedKeys = [
  43. 'blacklist',
  44. 'whitelist',
  45. 'transforms',
  46. 'storage',
  47. 'keyPrefix',
  48. 'migrate',
  49. ]
  50. bannedKeys.forEach(k => {
  51. if (!!optionsToTest[k])
  52. console.error(
  53. `redux-persist: invalid option passed to persistStore: "${k}". You may be incorrectly passing persistConfig into persistStore, whereas it should be passed into persistReducer.`
  54. )
  55. })
  56. }
  57. let boostrappedCb = cb || false
  58. let _pStore = createStore(
  59. persistorReducer,
  60. initialState,
  61. options && options.enhancer ? options.enhancer : undefined
  62. )
  63. let register = (key: string) => {
  64. _pStore.dispatch({
  65. type: REGISTER,
  66. key,
  67. })
  68. }
  69. let rehydrate = (key: string, payload: Object, err: any) => {
  70. let rehydrateAction = {
  71. type: REHYDRATE,
  72. payload,
  73. err,
  74. key,
  75. }
  76. // dispatch to `store` to rehydrate and `persistor` to track result
  77. store.dispatch(rehydrateAction)
  78. _pStore.dispatch(rehydrateAction)
  79. if (boostrappedCb && persistor.getState().bootstrapped) {
  80. boostrappedCb()
  81. boostrappedCb = false
  82. }
  83. }
  84. let persistor: Persistor = {
  85. ..._pStore,
  86. purge: () => {
  87. let results = []
  88. store.dispatch({
  89. type: PURGE,
  90. result: purgeResult => {
  91. results.push(purgeResult)
  92. },
  93. })
  94. return Promise.all(results)
  95. },
  96. flush: () => {
  97. let results = []
  98. store.dispatch({
  99. type: FLUSH,
  100. result: flushResult => {
  101. results.push(flushResult)
  102. },
  103. })
  104. return Promise.all(results)
  105. },
  106. pause: () => {
  107. store.dispatch({
  108. type: PAUSE,
  109. })
  110. },
  111. persist: () => {
  112. store.dispatch({ type: PERSIST, register, rehydrate })
  113. },
  114. }
  115. if (!(options && options.manualPersist)){
  116. persistor.persist()
  117. }
  118. return persistor
  119. }