├── .babelrc.js
├── .eslintrc.yml
├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── .prettierrc
├── CHANGELOG.md
├── LIBSIZE.md
├── LICENSE
├── README.md
├── docs
├── MigrationGuide-v5.md
├── PersistGate.md
├── api.md
├── hot-module-replacement.md
├── migrations.md
└── v5-migration-alternate.md
├── integration
├── README.md
└── react
│ └── package.json
├── package-lock.json
├── package.json
├── rollup.config.js
├── scripts
└── size-estimator.js
├── src
├── constants.ts
├── createMigrate.ts
├── createPersistoid.ts
├── createTransform.ts
├── getStoredState.ts
├── index.ts
├── integration
│ ├── getStoredStateMigrateV4.ts
│ └── react.ts
├── persistCombineReducers.ts
├── persistReducer.ts
├── persistStore.ts
├── purgeStoredState.ts
├── stateReconciler
│ ├── autoMergeLevel1.ts
│ ├── autoMergeLevel2.ts
│ └── hardSet.ts
├── storage
│ ├── createWebStorage.ts
│ ├── getStorage.ts
│ ├── index.ts
│ └── session.ts
└── types.ts
├── tests
├── complete.spec.ts
├── createPersistor.spec.ts
├── flush.spec.ts
├── persistCombineReducers.spec.ts
├── persistReducer.spec.ts
├── persistStore.spec.ts
└── utils
│ ├── brokenStorage.ts
│ ├── createMemoryStorage.ts
│ ├── find.ts
│ └── sleep.ts
├── tsconfig.json
└── types
└── types.d.ts
/.babelrc.js:
--------------------------------------------------------------------------------
1 | /**
2 | * Babel Configuration
3 | */
4 | module.exports = {
5 | presets: [
6 | [
7 | "@babel/preset-env"
8 | ],
9 | ],
10 | }
11 |
--------------------------------------------------------------------------------
/.eslintrc.yml:
--------------------------------------------------------------------------------
1 | ---
2 |
3 | parser: '@typescript-eslint/parser'
4 |
5 | globals:
6 | it: true
7 | expect: true
8 | describe: true
9 | test: true
10 | jest: true
11 |
12 | plugins:
13 | - '@typescript-eslint'
14 |
15 | extends:
16 | - eslint:recommended
17 | - plugin:@typescript-eslint/recommended
18 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: redux-persist ci
2 | on: [push, pull_request]
3 |
4 | jobs:
5 | # Label of the container job
6 | container-job:
7 | # Containers must run in Linux based operating systems
8 | runs-on: ubuntu-latest
9 | strategy:
10 | matrix:
11 | node-version: [14.x, 16.x]
12 |
13 | steps:
14 | - uses: actions/checkout@v2
15 | - name: Use Node.js ${{ matrix.node-version }}
16 | uses: actions/setup-node@v1
17 | with:
18 | node-version: ${{ matrix.node-version }}
19 | - name: npm install
20 | run: |
21 | npm install
22 | - name: run test
23 | run: |
24 | npm run test
25 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | es
2 | lib
3 | dist
4 | types
5 | .watchmanconfig
6 |
7 | # Logs
8 | logs
9 | *.log
10 | npm-debug.log*
11 |
12 | # Dependency directories
13 | node_modules
14 |
15 | # Optional npm cache directory
16 | .npm
17 |
18 | # Optional REPL history
19 | .node_repl_history
20 |
21 | .DS_Store
22 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | parser: "typescript"
2 | semi: false
3 | trailingComma: es5
4 | singleQuote: true
5 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 | All notable changes to this project (after v6.1.0) should be documented in this file.
3 |
4 | The format is (mostly) based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6 |
7 |
8 | ## [6.1.0] - 2021-10-17
9 | Thanks to [@smellman](https://github.com/smellman) for the TypeScript updates.
10 |
11 | ### Added
12 | - TypeScript support
13 | - GitHub Actions
14 |
15 | ### Changed
16 | - Move from Flow to TypeScript
17 | - Move from TravisCI to GitHub Actions ([.github/workflows/ci.yml](.github/workflows/ci.yml))
18 | - Version updates for some dependencies
19 |
20 | ### Removed
21 | - Flow
22 | - TravisCI
23 |
--------------------------------------------------------------------------------
/LIBSIZE.md:
--------------------------------------------------------------------------------
1 | ### Redux Persist Size Estimate
2 | The following is a history of size estimates in bytes. This is calculated as a rollup minified production build, excluding the size of redux which is an assumed peer dependency. YMMV.
3 |
4 | **v5.6.7**: 4724 Bytes
5 | **v5.6.8**: 4724 Bytes
6 | **v5.6.9**: 4724 Bytes
7 | **v5.6.10**: 4724 Bytes
8 | **v5.6.11**: 4724 Bytes
9 | **v5.6.12**: 4724 Bytes
10 | **v5.7.0**: 4893 Bytes
11 | **v5.7.1**: 4894 Bytes
12 | **v5.7.2**: 4894 Bytes
13 | **v5.8.0**: 4894 Bytes
14 | **v5.9.0**: 4894 Bytes
15 | **v5.9.1**: 4894 Bytes
16 | **v5.10.0**: 4356 Bytes
17 | **v6.0.0-pre1**: 17783 Bytes
18 | **v6.0.0-pre2**: 11878 Bytes
19 | **v6.0.0-pre2.0**: 11934 Bytes
20 | **v6.0.0-pre2.1**: 5525 Bytes
21 | **v6.0.0**: 12167 Bytes
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2017 Zack Story
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Redux Persist
2 | Persist and rehydrate a redux store.
3 |
4 | [](https://travis-ci.org/rt2zz/redux-persist) [](https://www.npmjs.com/package/redux-persist) [](https://www.npmjs.com/package/redux-persist)
5 |
6 | ## October 15th, 2021 - Move to TypeScript (Thanks [@smellman](https://github.com/smellman))
7 |
8 | As part of the work to upgrade the infrastructure used to build redux-persist, we're moving from Flow to TypeScript.
9 |
10 | - Move from Flow to TypeScript
11 | - Move from TravisCI to GitHub Actions ([.github/workflows/ci.yml](.github/workflows/ci.yml))
12 | - Version updates for some dependencies
13 |
14 | ## September 22nd, 2021 - Under New Management
15 |
16 | Redux Persist is a staple project for Redux developers, both on mobile and on the web. If you're here, it's likely because you need it now or have used it before and need to debug something, and like me have possibly struggled with making it work (especially with newer versions of things) and making it work with _your_ code because the examples you'll find around the internet are inconsistent.
17 |
18 | I ([@ckalika](https://github.com/ckalika)) spoke with [@rt2zz](https://github.com/rt2zz) about taking over maintenance of the project, and we agreed to give it a shot and see how we go. My priorities are as follows:
19 |
20 | 1. Go through and triage the existing issues
21 | - Separate them into bugs, feature requests, basic questions/requests for code samples, and issues that are either not project-specific or don't fall within the remit of the project (specific definitions and criteria will be posted in the future)
22 | - Determine the severity/urgency of each bug or feature request
23 | - Guestimate the size of them
24 | - Determine which are actionable immediately or in the short term
25 | - Establish some semblance of test criteria for each
26 |
27 |
28 | 2. Upgrade dependencies (where possible) so that we've got something building with modern versions
29 | * Note: Right now, it's about modernising the project infrastructure and build process without making breaking API changes
30 |
31 |
32 | 3. Go through the existing pull requests
33 | - Merge the ones that deal with documentation, code samples, etc.
34 | - Review and merge the ones that deal with open issues
35 | - Review and merge the ones that will require breaking changes and consult authors about `redux-persist@v7` (feature set and requirements to be defined)
36 |
37 |
38 | 4. Update the documentation
39 | - Split it out for both web and mobile
40 | - Providing code samples and test coverage for how to use the library
41 | - Provide or link to working examples that integrate with additional libraries (e.g. [RTK Query](https://redux-toolkit.js.org/rtk-query/overview)).
42 |
43 |
44 | 5. Improve testing and automation
45 | - [x] Move to GitHub Actions
46 | - [ ] Move from Ava to Jest
47 |
48 | There's a lot to do here, so I'll ask your patience and understanding as I work through it. If you have ideas for how to improve the library, the documentation, or the community, I'd love to hear them, and if you're submitting pull requests (or have submitted some previously), please reach out and help me understand what you're aiming to do with it.
49 |
50 | I'll try to get some discussions up to pull together ideas, so we can properly work out what the next version is likely to look like.
51 |
52 |
53 | ## v6 upgrade
54 | **Web**: no breaking changes
55 | **React Native**: Users must now explicitly pass their storage engine in. e.g.
56 | ```js
57 | import AsyncStorage from '@react-native-async-storage/async-storage';
58 |
59 | const persistConfig = {
60 | //...
61 | storage: AsyncStorage
62 | }
63 | ```
64 |
65 | ## Quickstart
66 | `npm install redux-persist`
67 |
68 | Usage Examples:
69 | 1. [Basic Usage](#basic-usage)
70 | 2. [Nested Persists](#nested-persists)
71 | 3. [Hot Module Replacement](./docs/hot-module-replacement.md)
72 | 4. Code Splitting [coming soon]
73 |
74 | #### Basic Usage
75 | Basic usage involves adding `persistReducer` and `persistStore` to your setup. **IMPORTANT** Every app needs to decide how many levels of state they want to "merge". The default is 1 level. Please read through the [state reconciler docs](#state-reconciler) for more information.
76 |
77 | ```js
78 | // configureStore.js
79 |
80 | import { createStore } from 'redux'
81 | import { persistStore, persistReducer } from 'redux-persist'
82 | import storage from 'redux-persist/lib/storage' // defaults to localStorage for web
83 |
84 | import rootReducer from './reducers'
85 |
86 | const persistConfig = {
87 | key: 'root',
88 | storage,
89 | }
90 |
91 | const persistedReducer = persistReducer(persistConfig, rootReducer)
92 |
93 | export default () => {
94 | let store = createStore(persistedReducer)
95 | let persistor = persistStore(store)
96 | return { store, persistor }
97 | }
98 | ```
99 |
100 | If you are using react, wrap your root component with [PersistGate](./docs/PersistGate.md). This delays the rendering of your app's UI until your persisted state has been retrieved and saved to redux. **NOTE** the `PersistGate` loading prop can be null, or any react instance, e.g. `loading={}`
101 |
102 | ```js
103 | import { PersistGate } from 'redux-persist/integration/react'
104 |
105 | // ... normal setup, create store and persistor, import components etc.
106 |
107 | const App = () => {
108 | return (
109 |
110 |
111 |
112 |
113 |
114 | );
115 | };
116 | ```
117 |
118 | ## API
119 | [Full API](./docs/api.md)
120 |
121 | #### `persistReducer(config, reducer)`
122 | - arguments
123 | - [**config**](https://github.com/rt2zz/redux-persist/blob/master/src/types.js#L13-L27) *object*
124 | - required config: `key, storage`
125 | - notable other config: `whitelist, blacklist, version, stateReconciler, debug`
126 | - **reducer** *function*
127 | - any reducer will work, typically this would be the top level reducer returned by `combineReducers`
128 | - returns an enhanced reducer
129 |
130 | #### `persistStore(store, [config, callback])`
131 | - arguments
132 | - **store** *redux store* The store to be persisted.
133 | - **config** *object* (typically null)
134 | - If you want to avoid that the persistence starts immediately after calling `persistStore`, set the option manualPersist. Example: `{ manualPersist: true }` Persistence can then be started at any point with `persistor.persist()`. You usually want to do this if your storage is not ready when the `persistStore` call is made.
135 | - **callback** *function* will be called after rehydration is finished.
136 | - returns **persistor** object
137 |
138 | #### `persistor object`
139 | - the persistor object is returned by persistStore with the following methods:
140 | - `.purge()`
141 | - purges state from disk and returns a promise
142 | - `.flush()`
143 | - immediately writes all pending state to disk and returns a promise
144 | - `.pause()`
145 | - pauses persistence
146 | - `.persist()`
147 | - resumes persistence
148 |
149 | ## State Reconciler
150 | State reconcilers define how incoming state is merged in with initial state. It is critical to choose the right state reconciler for your state. There are three options that ship out of the box, let's look at how each operates:
151 |
152 | 1. **hardSet** (`import hardSet from 'redux-persist/lib/stateReconciler/hardSet'`)
153 | This will hard set incoming state. This can be desirable in some cases where persistReducer is nested deeper in your reducer tree, or if you do not rely on initialState in your reducer.
154 | - **incoming state**: `{ foo: incomingFoo }`
155 | - **initial state**: `{ foo: initialFoo, bar: initialBar }`
156 | - **reconciled state**: `{ foo: incomingFoo }` // note bar has been dropped
157 | 2. **autoMergeLevel1** (default)
158 | This will auto merge one level deep. Auto merge means if the some piece of substate was modified by your reducer during the REHYDRATE action, it will skip this piece of state. Level 1 means it will shallow merge 1 level deep.
159 | - **incoming state**: `{ foo: incomingFoo }`
160 | - **initial state**: `{ foo: initialFoo, bar: initialBar }`
161 | - **reconciled state**: `{ foo: incomingFoo, bar: initialBar }` // note incomingFoo overwrites initialFoo
162 | 3. **autoMergeLevel2** (`import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2'`)
163 | This acts just like autoMergeLevel1, except it shallow merges two levels
164 | - **incoming state**: `{ foo: incomingFoo }`
165 | - **initial state**: `{ foo: initialFoo, bar: initialBar }`
166 | - **reconciled state**: `{ foo: mergedFoo, bar: initialBar }` // note: initialFoo and incomingFoo are shallow merged
167 |
168 | #### Example
169 | ```js
170 | import hardSet from 'redux-persist/lib/stateReconciler/hardSet'
171 |
172 | const persistConfig = {
173 | key: 'root',
174 | storage,
175 | stateReconciler: hardSet,
176 | }
177 | ```
178 |
179 | ## React Integration
180 | Redux persist ships with react integration as a convenience. The `PersistGate` component is the recommended way to delay rendering until persistence is complete. It works in one of two modes:
181 | 1. `loading` prop: The provided loading value will be rendered until persistence is complete at which point children will be rendered.
182 | 2. function children: The function will be invoked with a single `bootstrapped` argument. When bootstrapped is true, persistence is complete and it is safe to render the full app. This can be useful for adding transition animations.
183 |
184 | ## Blacklist & Whitelist
185 | By Example:
186 | ```js
187 | // BLACKLIST
188 | const persistConfig = {
189 | key: 'root',
190 | storage: storage,
191 | blacklist: ['navigation'] // navigation will not be persisted
192 | };
193 |
194 | // WHITELIST
195 | const persistConfig = {
196 | key: 'root',
197 | storage: storage,
198 | whitelist: ['navigation'] // only navigation will be persisted
199 | };
200 | ```
201 |
202 | ## Nested Persists
203 | Nested persist can be useful for including different storage adapters, code splitting, or deep filtering. For example while blacklist and whitelist only work one level deep, but we can use a nested persist to blacklist a deeper value:
204 | ```js
205 | import { combineReducers } from 'redux'
206 | import { persistReducer } from 'redux-persist'
207 | import storage from 'redux-persist/lib/storage'
208 |
209 | import { authReducer, otherReducer } from './reducers'
210 |
211 | const rootPersistConfig = {
212 | key: 'root',
213 | storage: storage,
214 | blacklist: ['auth']
215 | }
216 |
217 | const authPersistConfig = {
218 | key: 'auth',
219 | storage: storage,
220 | blacklist: ['somethingTemporary']
221 | }
222 |
223 | const rootReducer = combineReducers({
224 | auth: persistReducer(authPersistConfig, authReducer),
225 | other: otherReducer,
226 | })
227 |
228 | export default persistReducer(rootPersistConfig, rootReducer)
229 | ```
230 |
231 | ## Migrations
232 | `persistReducer` has a general purpose "migrate" config which will be called after getting stored state but before actually reconciling with the reducer. It can be any function which takes state as an argument and returns a promise to return a new state object.
233 |
234 | Redux Persist ships with `createMigrate`, which helps create a synchronous migration for moving from any version of stored state to the current state version. [[Additional information]](./docs/migrations.md)
235 |
236 | ## Transforms
237 | Transforms allow you to customize the state object that gets persisted and rehydrated.
238 |
239 | There are several libraries that tackle some common implementations for transforms.
240 | - [immutable](https://github.com/rt2zz/redux-persist-transform-immutable) - support immutable reducers
241 | - [seamless-immutable](https://github.com/hilkeheremans/redux-persist-seamless-immutable) - support seamless-immutable reducers
242 | - [compress](https://github.com/rt2zz/redux-persist-transform-compress) - compress your serialized state with lz-string
243 | - [encrypt](https://github.com/maxdeviant/redux-persist-transform-encrypt) - encrypt your serialized state with AES
244 | - [filter](https://github.com/edy/redux-persist-transform-filter) - store or load a subset of your state
245 | - [filter-immutable](https://github.com/actra-development/redux-persist-transform-filter-immutable) - store or load a subset of your state with support for immutablejs
246 | - [expire](https://github.com/gabceb/redux-persist-transform-expire) - expire a specific subset of your state based on a property
247 | - [expire-reducer](https://github.com/kamranahmedse/redux-persist-expire) - more flexible alternative to expire transformer above with more options
248 |
249 | When the state object gets persisted, it first gets serialized with `JSON.stringify()`. If parts of your state object are not mappable to JSON objects, the serialization process may transform these parts of your state in unexpected ways. For example, the javascript [Set](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Set) type does not exist in JSON. When you try to serialize a Set via `JSON.stringify()`, it gets converted to an empty object. Probably not what you want.
250 |
251 | Below is a Transform that successfully persists a Set property, which simply converts it to an array and back. In this way, the Set gets converted to an Array, which is a recognized data structure in JSON. When pulled out of the persisted store, the array gets converted back to a Set before being saved to the redux store.
252 |
253 | ```js
254 | import { createTransform } from 'redux-persist';
255 |
256 | const SetTransform = createTransform(
257 | // transform state on its way to being serialized and persisted.
258 | (inboundState, key) => {
259 | // convert mySet to an Array.
260 | return { ...inboundState, mySet: [...inboundState.mySet] };
261 | },
262 | // transform state being rehydrated
263 | (outboundState, key) => {
264 | // convert mySet back to a Set.
265 | return { ...outboundState, mySet: new Set(outboundState.mySet) };
266 | },
267 | // define which reducers this transform gets called for.
268 | { whitelist: ['someReducer'] }
269 | );
270 |
271 | export default SetTransform;
272 | ```
273 |
274 | The `createTransform` function takes three parameters.
275 | 1. An "inbound" function that gets called right before state is persisted (optional).
276 | 2. An "outbound" function that gets called right before state is rehydrated (optional).
277 | 3. A config object that determines which keys in your state will be transformed (by default no keys are transformed).
278 |
279 | In order to take effect transforms need to be added to a `PersistReducer`’s config object.
280 |
281 | ```
282 | import storage from 'redux-persist/lib/storage';
283 | import { SetTransform } from './transforms';
284 |
285 | const persistConfig = {
286 | key: 'root',
287 | storage: storage,
288 | transforms: [SetTransform]
289 | };
290 | ```
291 |
292 | ## Storage Engines
293 | - **localStorage** `import storage from 'redux-persist/lib/storage'`
294 | - **sessionStorage** `import storageSession from 'redux-persist/lib/storage/session'`
295 | - **[electron storage](https://github.com/psperber/redux-persist-electron-storage)** Electron support via [electron store](https://github.com/sindresorhus/electron-store)
296 | - **[redux-persist-cookie-storage](https://github.com/abersager/redux-persist-cookie-storage)** Cookie storage engine, works in browser and Node.js, for universal / isomorphic apps
297 | - **[redux-persist-expo-filesystem](https://github.com/t73liu/redux-persist-expo-filesystem)** react-native, similar to redux-persist-filesystem-storage but does not require linking or ejecting CRNA/Expo app. Only available if using Expo SDK (Expo, create-react-native-app, standalone).
298 | - **[redux-persist-expo-securestore](https://github.com/Cretezy/redux-persist-expo-securestore)** react-native, for sensitive information using Expo's SecureStore. Only available if using Expo SDK (Expo, create-react-native-app, standalone).
299 | - **[redux-persist-fs-storage](https://github.com/leethree/redux-persist-fs-storage)** react-native-fs engine
300 | - **[redux-persist-filesystem-storage](https://github.com/robwalkerco/redux-persist-filesystem-storage)** react-native, to mitigate storage size limitations in android ([#199](https://github.com/rt2zz/redux-persist/issues/199), [#284](https://github.com/rt2zz/redux-persist/issues/284))
301 | **[redux-persist-indexeddb-storage](https://github.com/machester4/redux-persist-indexeddb-storage)** recommended for web via [localForage](https://github.com/localForage/localForage)
302 | - **[redux-persist-node-storage](https://github.com/pellejacobs/redux-persist-node-storage)** for use in nodejs environments.
303 | - **[redux-persist-pouchdb](https://github.com/yanick/redux-persist-pouchdb)** Storage engine for PouchDB.
304 | - **[redux-persist-sensitive-storage](https://github.com/CodingZeal/redux-persist-sensitive-storage)** react-native, for sensitive information (uses [react-native-sensitive-info](https://github.com/mCodex/react-native-sensitive-info)).
305 | - **[redux-persist-weapp-storage](https://github.com/cuijiemmx/redux-casa/tree/master/packages/redux-persist-weapp-storage)** Storage engine for wechat mini program, also compatible with wepy
306 | - **[redux-persist-webextension-storage](https://github.com/ssorallen/redux-persist-webextension-storage)** Storage engine for browser (Chrome, Firefox) web extension storage
307 | - **[@bankify/redux-persist-realm](https://github.com/bankifyio/redux-persist-realm)** Storage engine for Realm database, you will need to install Realm first
308 | - **custom** any conforming storage api implementing the following methods: `setItem` `getItem` `removeItem`. (**NB**: These methods must support promises)
309 |
310 | ## Community & Contributing
311 |
312 | I will be updating this section shortly. If you have a pull request that you've got outstanding, please reach out and I will try to review it and get it integrated. As we've shifted to TypeScript, that may necessitate some changes, but I'm happy to help in that regard, wherever I can.
313 |
--------------------------------------------------------------------------------
/docs/MigrationGuide-v5.md:
--------------------------------------------------------------------------------
1 | ## v5 Breaking Changes
2 | There are three important breaking changes.
3 | 1. api has changed as described in the [migration](#migration-from-v4-to-v5) section below.
4 | 2. state with cycles is no longer serialized using `json-stringify-safe`, and will instead noop.
5 | 3. state methods can no longer be overridden which means all top level state needs to be plain objects. `redux-persist-transform-immutable` will continue to operate as before as it works on substate, not top level state.
6 |
7 | Additionally v5 does not yet have typescript bindings.
8 |
9 | ## Migration from v4 to v5
10 | **WARNING** v4 stored state is not compatible with v5. If you upgrade a v4 application, your users will lose their stored state upon upgrade. You can try the (highly) experimental [v4 -> v5 state migration](#experimental-v4-to-v5-state-migration) if you please. Feedback appreciated.
11 |
12 | Standard Usage:
13 | - remove **autoRehydrate**
14 | - changes to **persistStore**:
15 | - 1. remove config argument (or replace with an null if you are using a callback)
16 | - 2. remove all arguments from the callback. If you need state you can call `store.getState()`
17 | - 3. all constants (ex: `REHYDRATE`, `PURGE`) has moved from `redux-persist/constants` to the root module.
18 | - replace `combineReducers` with **persistCombineReducers**
19 | - e.g. `let reducer = persistCombineReducers(config, reducers)`
20 | - changes to **config**:
21 | - `key` is now required. Can be set to anything, e.g. 'primary'
22 | - `storage` is now required. For default storage: `import storage from 'redux-persist/lib/storage'`
23 |
24 | ```diff
25 | -import { REHYDRATE, PURGE } from 'redux-persist/constants'
26 | -import { combineReducers } from 'redux'
27 | +import { REHYDRATE, PURGE, persistCombineReducers } from 'redux-persist'
28 | +import storage from 'redux-persist/lib/storage' // or whatever storage you are using
29 |
30 | const config = {
31 | + key: 'primary',
32 | + storage
33 | }
34 |
35 | -let reducer = combineReducers(reducers)
36 | +let reducer = persistCombineReducers(config, reducers)
37 |
38 | const store = createStore(
39 | reducer,
40 | undefined,
41 | compose(
42 | applyMiddleware(...),
43 | - autoRehydrate()
44 | )
45 | )
46 |
47 | const callback = ()
48 |
49 | persistStore(
50 | store,
51 | - config,
52 | + null,
53 | (
54 | - err, restoredState
55 | ) => {
56 | + store.getState() // if you want to get restoredState
57 | }
58 | )
59 | ```
60 |
61 | Recommended Additions
62 | - use new **PersistGate** to delay rendering until rehydration is complete
63 | - `import { PersistGate } from 'redux-persist/lib/integration/react'`
64 | - set `config.debug = true` to get useful logging
65 |
66 | If your implementation uses getStoredState + createPersistor see [alternate migration](./v5-migration-alternate.md)
67 |
68 | ## Why v5
69 | Long story short, the changes are required in order to support new use cases
70 | - code splitting reducers
71 | - easier to ship persist support inside of other libs (e.g. redux-offline)
72 | - ability to colocate persistence rules with the reducer it pertains to
73 | - first class migration support
74 | - enable PersistGate react component which blocks rendering until persistence is complete (and enables similar patterns for integration)
75 | - possible to nest persistence
76 | - guarantee consistent state atoms
77 | - better debugability and extensibility
78 |
79 | ## Experimental v4 to v5 State Migration
80 | - **warning: this method is completely untested**
81 | - v5 getStoredState is not compatible with v4, so by default v5 will cause all of the persisted state from v4 to disappear on first run
82 | - v5 ships with an experimental v4 -> v5 migration that works by overriding the default getStoredState implementation
83 | **Warning** this is completely untested, please try and report back with any issues.
84 | ```js
85 | import getStoredStateMigrateV4 from 'redux-persist/lib/integration/getStoredStateMigrateV4'
86 | // ...
87 | persistReducer({
88 | // ...
89 | getStoredState: getStoredStateMigrateV4(yourOldV4Config)
90 | }, baseReducer)
91 | ```
92 |
--------------------------------------------------------------------------------
/docs/PersistGate.md:
--------------------------------------------------------------------------------
1 | `PersistGate` delays the rendering of your app's UI until your persisted state has been retrieved and saved to redux.
2 |
3 | **NOTE**: the `loading` prop can be `null` or any react instance to show during loading (e.g. a splash screen), for example `loading={}`.
4 |
5 | Example usage:
6 |
7 | ```js
8 | import { PersistGate } from 'redux-persist/es/integration/react'
9 |
10 | import configureStore from './store/configureStore'
11 |
12 | const { persistor, store } = configureStore()
13 |
14 | const onBeforeLift = () => {
15 | // take some action before the gate lifts
16 | }
17 |
18 | export default () => (
19 |
20 | }
22 | onBeforeLift={onBeforeLift}
23 | persistor={persistor}>
24 |
25 |
26 |
27 | )
28 | ```
29 |
--------------------------------------------------------------------------------
/docs/api.md:
--------------------------------------------------------------------------------
1 | # Redux Persist API
2 | ---
3 | ## Standard API
4 | - [persistReducer](#persistreducerconfig-reducer)([config](#type-persistconfig), reducer)
5 | - [persistStore](#persiststorestore-config-callback)(store)
6 | - [createMigrate](#createmigratemigrations-config)([migrations](#type-migrationmanifest))
7 | ### `persistReducer(config, reducer)`
8 |
9 | ```js
10 | persistReducer(
11 | config: PersistConfig,
12 | reducer: Reducer,
13 | ): Reducer
14 | ```
15 |
16 | Where Reducer is any reducer `(state, action) => state` and PersistConfig is [defined below](#type-persistconfig)
17 |
18 | ### `persistStore(store, config, callback)`
19 | ```js
20 | persistStore(
21 | store: Store,
22 | config?: { enhancer?: Function },
23 | callback?: () => {}
24 | ): Persistor
25 | ```
26 |
27 | Where Persistor is [defined below](#type-persistor)
28 |
29 | ### `createMigrate(migrations, config)`
30 | ```js
31 | createMigrate(
32 | migrations: MigrationManifest,
33 | config?: { debug: boolean }
34 | )
35 | ```
36 |
37 | ### `type Persistor`
38 | ```js
39 | {
40 | purge: () => Promise,
41 | flush: () => Promise,
42 | }
43 | ```
44 |
45 | The Persistor is a redux store unto itself, plus
46 | 1. the `purge()` method for clearing out stored state.
47 | 2. the `flush()` method for flushing all pending state serialization and immediately write to disk
48 |
49 | `purge()` method only clear the content of the storage, leaving the internal data of `redux` untouched. To clean it instead, you can use the [redux-reset](https://github.com/wwayne/redux-reset) module.
50 |
51 | ### `type PersistConfig`
52 | ```js
53 | {
54 | key: string, // the key for the persist
55 | storage: Object, // the storage adapter, following the AsyncStorage api
56 | version?: number, // the state version as an integer (defaults to -1)
57 | blacklist?: Array, // do not persist these keys
58 | whitelist?: Array, // only persist these keys
59 | migrate?: (Object, number) => Promise