Redux Persist 最佳實踐
希望可以幫助大家使用和了解redux-persist的相關(guān)能力
接入
npm i --save redux-persist
如果你使用了
immutable
npm i --save redux-persist-immutable
使用
// store.js
import { persistStore, autoRehydrate } from 'redux-persist'
// or
// import { persistStore, autoRehydrate } from 'redux-persist-immutable'
const store = createStore(
...
autoRehydrate()
)
persistStore(store, {storage: AsyncStorage})
本地存儲
redux-persist react native 端本地存儲指定使用AsyncStorage
。Android是以K-V的形式存儲在本地sqlite中。
iOS 是直接存沙盒文件了
Android
- key: 'reduxPersist:' + reducer key
- value: json序列化后的state
iOS
- 整個狀態(tài)樹保存到沙盒
RCTAsyncLocalStorage_V1
目錄中的manifest.json
中 - 會判斷value內(nèi)容的大小,當超過1024的時候會存入當獨的文件。文件名為key的MD5
配置黑白名單
const config = {
storage: AsyncStorage,
blacklist:['weather'],
whitelist:['display ']
}
persistStore(store, config)
redux-persist 支持配置和黑名單。僅僅持久化白名單中的數(shù)據(jù)或者不持久化黑名單中的數(shù)據(jù)。
由于大部分情況下我們的state都會非常的大。強烈建議建議大家使用白名單對持久化數(shù)據(jù)做過濾。
transforms
支持在數(shù)據(jù)保存和還原之前做狀態(tài)的轉(zhuǎn)換。
其本身提供了一些常用的transforms
- immutable - 支持immutable狀態(tài)的支持
-
compress - 使用
lz-string
對數(shù)據(jù)做壓縮 - encrypt - 使用AES 對數(shù)據(jù)做加密
- filter - 對數(shù)據(jù)做過濾
- filter-immutable - 對數(shù)據(jù)做過濾,針對immutable
- expire - 對持久化數(shù)據(jù)指定過期時間
組合使用
需要考慮掛載順序?qū)?shù)據(jù)影響
persistStore(store, {
transforms: [expireTransform,immutableTransform,encryptTransform]
});
當然還可以根據(jù)自己的需求進行自定義,并不復雜
autoRehydrate
我們知道persist做了緩存數(shù)據(jù)的加載,這里就涉及到三個狀態(tài),初始化的state、緩存state、reducer后的state。那么這三者是如何合并的?這是一個問題。
autoRehydrate
就是用來解決這個問題的。
其參數(shù)stateReconciler
中定義了合并規(guī)則。
如果沒有定義這使用默認的defaultStateReconciler
- 1、如果是初始化state中沒有可以忽略
- 2、如果緩存state中的value是null/undefined 忽略
- 3、如果初始化state和reducer后的state值不同,優(yōu)先使用reducer后的state
- 4、如果state value為普通對象這進行合并、不是普通對象則進行強制替換
migrate
每次版本升級都或多少伴隨著state的變化,那么新state和持久化的state之間應該如何保持一致性?
之前可能會有一些簡單粗暴的處理,比如刪除緩存。
而中間件migrate就是解決這個問題的優(yōu)雅方案。他可以指定對應state的版本。通過定義manifest
來描述每個版本的變化情況。從而實現(xiàn)新老state的結(jié)構(gòu)一致。
如:
import { compose, createStore } from 'redux'
import { persistStore, autoRehydrate } from 'redux-persist'
import createMigration from 'redux-persist-migrate'
const manifest = {
1: (state) => ({...state, staleReducer: undefined})
2: (state) => ({...state, app: {...state.app, staleKey: undefined}})
}
let reducerKey = 'app'
const migration = createMigration(manifest, reducerKey)
const enhancer = compose(migration, autoRehydrate())
const store = createStore(reducer, null, enhancer)
persistStore(store)
migrate
找出reduce的版本號,并遍歷執(zhí)行manifest中大于此版本號的方法。最終返回一個最新版本號寫入reduce.version
中!
debounce
persist
的寫緩存時機 store
監(jiān)聽器觸發(fā)的時候,也就是狀態(tài)發(fā)生變化的時候。但是如果我們頻繁操作 store 就會出現(xiàn)大量的 native 讀寫。影響性能,于是 persist 提供了 debounce 機制。store 監(jiān)聽器觸發(fā)的時候并不立刻執(zhí)行,而是使用setInterval
做了一下延時。 保證指定時間內(nèi)只執(zhí)行一次。
keyPrefix
上面我們知道數(shù)據(jù)的存儲是以key: 'reduxPersist:' + reducer key
的類型存儲的。默認 keyPrefix
是 reduxPersist
。 這個是可以使用 config.keyPrefix
進行修改定制的。更具不同的業(yè)務定義不同的 key 進行業(yè)務區(qū)分。也很好的避免了數(shù)據(jù)覆蓋的問題
問題
persist store是否可以共享?
persist 本質(zhì)上是基于同一份Native存儲的,所以本身就是共享的。如要訪問其他SDK的state則需要加上添加上對應的key
key沖突?
可能會沖突,所以建議在reducer name中加上前綴?
persist 間緩存隔離
需要定制修改persist,將不同的SDK state 存入不同的數(shù)據(jù)庫!
什么時候讀緩存?
persistStore 執(zhí)行的時候。
什么時候?qū)懢彺?/h4>
Store 監(jiān)聽器觸發(fā)的時候,也就是狀態(tài)發(fā)生變化時。