Redux Persist 最佳實(shí)踐
希望可以幫助大家使用和了解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})
本地存儲(chǔ)
redux-persist react native 端本地存儲(chǔ)指定使用AsyncStorage
卵贱。Android是以K-V的形式存儲(chǔ)在本地sqlite中蚯妇。
iOS 是直接存沙盒文件了
Android
- key: 'reduxPersist:' + reducer key
- value: json序列化后的state
iOS
- 整個(gè)狀態(tài)樹保存到沙盒
RCTAsyncLocalStorage_V1
目錄中的manifest.json
中 - 會(huì)判斷value內(nèi)容的大小滞详,當(dāng)超過1024的時(shí)候會(huì)存入當(dāng)獨(dú)的文件。文件名為key的MD5
配置黑白名單
const config = {
storage: AsyncStorage,
blacklist:['weather'],
whitelist:['display ']
}
persistStore(store, config)
redux-persist 支持配置和黑名單拂共。僅僅持久化白名單中的數(shù)據(jù)或者不持久化黑名單中的數(shù)據(jù)牺弄。
由于大部分情況下我們的state都會(huì)非常的大。強(qiáng)烈建議建議大家使用白名單對(duì)持久化數(shù)據(jù)做過濾宜狐。
transforms
支持在數(shù)據(jù)保存和還原之前做狀態(tài)的轉(zhuǎn)換。
其本身提供了一些常用的transforms
- immutable - 支持immutable狀態(tài)的支持
-
compress - 使用
lz-string
對(duì)數(shù)據(jù)做壓縮 - encrypt - 使用AES 對(duì)數(shù)據(jù)做加密
- filter - 對(duì)數(shù)據(jù)做過濾
- filter-immutable - 對(duì)數(shù)據(jù)做過濾抚恒,針對(duì)immutable
- expire - 對(duì)持久化數(shù)據(jù)指定過期時(shí)間
組合使用
需要考慮掛載順序?qū)?shù)據(jù)影響
persistStore(store, {
transforms: [expireTransform,immutableTransform,encryptTransform]
});
當(dāng)然還可以根據(jù)自己的需求進(jìn)行自定義,并不復(fù)雜
autoRehydrate
我們知道persist做了緩存數(shù)據(jù)的加載俭驮,這里就涉及到三個(gè)狀態(tài),初始化的state混萝、緩存state、reducer后的state譬圣。那么這三者是如何合并的瓮恭?這是一個(gè)問題厘熟。
autoRehydrate
就是用來解決這個(gè)問題的。
其參數(shù)stateReconciler
中定義了合并規(guī)則绳姨。
如果沒有定義這使用默認(rèn)的defaultStateReconciler
- 1登澜、如果是初始化state中沒有可以忽略
- 2飘庄、如果緩存state中的value是null/undefined 忽略
- 3、如果初始化state和reducer后的state值不同跪削,優(yōu)先使用reducer后的state
- 4、如果state value為普通對(duì)象這進(jìn)行合并碾盐、不是普通對(duì)象則進(jìn)行強(qiáng)制替換
migrate
每次版本升級(jí)都或多少伴隨著state的變化晃跺,那么新state和持久化的state之間應(yīng)該如何保持一致性?
之前可能會(huì)有一些簡單粗暴的處理毫玖,比如刪除緩存掀虎。
而中間件migrate就是解決這個(gè)問題的優(yōu)雅方案。他可以指定對(duì)應(yīng)state的版本付枫。通過定義manifest
來描述每個(gè)版本的變化情況烹玉。從而實(shí)現(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的版本號(hào)阐滩,并遍歷執(zhí)行manifest中大于此版本號(hào)的方法二打。最終返回一個(gè)最新版本號(hào)寫入reduce.version
中!
debounce
persist
的寫緩存時(shí)機(jī) store
監(jiān)聽器觸發(fā)的時(shí)候掂榔,也就是狀態(tài)發(fā)生變化的時(shí)候址儒。但是如果我們頻繁操作 store 就會(huì)出現(xiàn)大量的 native 讀寫。影響性能衅疙,于是 persist 提供了 debounce 機(jī)制莲趣。store 監(jiān)聽器觸發(fā)的時(shí)候并不立刻執(zhí)行,而是使用setInterval
做了一下延時(shí)饱溢。 保證指定時(shí)間內(nèi)只執(zhí)行一次喧伞。
keyPrefix
上面我們知道數(shù)據(jù)的存儲(chǔ)是以key: 'reduxPersist:' + reducer key
的類型存儲(chǔ)的。默認(rèn) keyPrefix
是 reduxPersist
绩郎。 這個(gè)是可以使用 config.keyPrefix
進(jìn)行修改定制的潘鲫。更具不同的業(yè)務(wù)定義不同的 key 進(jìn)行業(yè)務(wù)區(qū)分。也很好的避免了數(shù)據(jù)覆蓋的問題
問題
persist store是否可以共享肋杖?
persist 本質(zhì)上是基于同一份Native存儲(chǔ)的溉仑,所以本身就是共享的。如要訪問其他SDK的state則需要加上添加上對(duì)應(yīng)的key
key沖突状植?
可能會(huì)沖突浊竟,所以建議在reducer name中加上前綴怨喘?
persist 間緩存隔離
需要定制修改persist,將不同的SDK state 存入不同的數(shù)據(jù)庫振定!
什么時(shí)候讀緩存必怜?
persistStore 執(zhí)行的時(shí)候。
什么時(shí)候?qū)懢彺?/h4>
Store 監(jiān)聽器觸發(fā)的時(shí)候后频,也就是狀態(tài)發(fā)生變化時(shí)梳庆。