getStoredStateMigrateV4.js.flow 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. // @flow
  2. import getStoredStateV5 from '../getStoredState'
  3. import type { PersistConfig, Transform } from '../types'
  4. type V4Config = {
  5. storage?: Object,
  6. serialize: boolean,
  7. keyPrefix?: string,
  8. transforms?: Array<Transform>,
  9. blacklist?: Array<string>,
  10. whitelist?: Array<string>,
  11. }
  12. export default function getStoredState(v4Config: V4Config) {
  13. return function(v5Config: PersistConfig) {
  14. return getStoredStateV5(v5Config).then(state => {
  15. if (state) return state
  16. else return getStoredStateV4(v4Config)
  17. })
  18. }
  19. }
  20. const KEY_PREFIX = 'reduxPersist:'
  21. function hasLocalStorage() {
  22. if (typeof self !== 'object' || !('localStorage' in self)) {
  23. return false
  24. }
  25. try {
  26. let storage = self.localStorage
  27. const testKey = `redux-persist localStorage test`
  28. storage.setItem(testKey, 'test')
  29. storage.getItem(testKey)
  30. storage.removeItem(testKey)
  31. } catch (e) {
  32. if (process.env.NODE_ENV !== 'production')
  33. console.warn(
  34. `redux-persist localStorage test failed, persistence will be disabled.`
  35. )
  36. return false
  37. }
  38. return true
  39. }
  40. let noop = (...args: any) => {
  41. /* noop */ return null
  42. }
  43. const noStorage = {
  44. getItem: noop,
  45. setItem: noop,
  46. removeItem: noop,
  47. getAllKeys: noop,
  48. }
  49. const createAsyncLocalStorage = () => {
  50. if (!hasLocalStorage()) return noStorage
  51. let localStorage = self.localStorage
  52. return {
  53. getAllKeys: function(cb) {
  54. try {
  55. var keys = []
  56. for (var i = 0; i < localStorage.length; i++) {
  57. keys.push(localStorage.key(i))
  58. }
  59. cb(null, keys)
  60. } catch (e) {
  61. cb(e)
  62. }
  63. },
  64. getItem(key, cb) {
  65. try {
  66. var s = localStorage.getItem(key)
  67. cb(null, s)
  68. } catch (e) {
  69. cb(e)
  70. }
  71. },
  72. setItem(key, string, cb) {
  73. try {
  74. localStorage.setItem(key, string)
  75. cb(null)
  76. } catch (e) {
  77. cb(e)
  78. }
  79. },
  80. removeItem(key, cb) {
  81. try {
  82. localStorage.removeItem(key)
  83. cb && cb(null)
  84. } catch (e) {
  85. cb(e)
  86. }
  87. },
  88. }
  89. }
  90. function getStoredStateV4(v4Config: V4Config) {
  91. return new Promise((resolve, reject) => {
  92. let storage = v4Config.storage || createAsyncLocalStorage()
  93. const deserializer =
  94. v4Config.serialize === false
  95. ? data => data
  96. : (serial: string) => JSON.parse(serial)
  97. const blacklist = v4Config.blacklist || []
  98. const whitelist = v4Config.whitelist || false
  99. const transforms = v4Config.transforms || []
  100. const keyPrefix =
  101. v4Config.keyPrefix !== undefined ? v4Config.keyPrefix : KEY_PREFIX
  102. // fallback getAllKeys to `keys` if present (LocalForage compatability)
  103. if (storage.keys && !storage.getAllKeys)
  104. storage = { ...storage, getAllKeys: storage.keys }
  105. let restoredState = {}
  106. let completionCount = 0
  107. storage.getAllKeys((err, allKeys = []) => {
  108. if (err) {
  109. if (process.env.NODE_ENV !== 'production')
  110. console.warn(
  111. 'redux-persist/getStoredState: Error in storage.getAllKeys'
  112. )
  113. return reject(err)
  114. }
  115. let persistKeys = allKeys
  116. .filter(key => key.indexOf(keyPrefix) === 0)
  117. .map(key => key.slice(keyPrefix.length))
  118. let keysToRestore = persistKeys.filter(passWhitelistBlacklist)
  119. let restoreCount = keysToRestore.length
  120. if (restoreCount === 0) resolve(undefined)
  121. keysToRestore.forEach(key => {
  122. storage.getItem(createStorageKey(key), (err, serialized) => {
  123. if (err && process.env.NODE_ENV !== 'production')
  124. console.warn(
  125. 'redux-persist/getStoredState: Error restoring data for key:',
  126. key,
  127. err
  128. )
  129. else restoredState[key] = rehydrate(key, serialized)
  130. completionCount += 1
  131. if (completionCount === restoreCount) resolve(restoredState)
  132. })
  133. })
  134. })
  135. function rehydrate(key: string, serialized: ?string) {
  136. let state = null
  137. try {
  138. let data = serialized ? deserializer(serialized) : undefined
  139. state = transforms.reduceRight((subState, transformer) => {
  140. return transformer.out(subState, key, {})
  141. }, data)
  142. } catch (err) {
  143. if (process.env.NODE_ENV !== 'production')
  144. console.warn(
  145. 'redux-persist/getStoredState: Error restoring data for key:',
  146. key,
  147. err
  148. )
  149. }
  150. return state
  151. }
  152. function passWhitelistBlacklist(key) {
  153. if (whitelist && whitelist.indexOf(key) === -1) return false
  154. if (blacklist.indexOf(key) !== -1) return false
  155. return true
  156. }
  157. function createStorageKey(key) {
  158. return `${keyPrefix}${key}`
  159. }
  160. })
  161. }
  162. function defaultDeserializer(serial: string) {
  163. return JSON.parse(serial)
  164. }