問題引入
描述
上次使用Redux,最終實現(xiàn)了兄弟組件之間的通信--點擊左邊的導航欄(左邊藍色部分)蝙云,右邊的頭部(紅色部分)會改變成對應的文字氓皱。
之后又用Redux,準備實現(xiàn)該界面(訂單管理)的另一個功能--選中表格中的一欄勃刨,點擊上面的詳細頁面按鈕(第二個藍色按鈕)波材,可以打開一個新頁面,并在該頁面上顯示選中表格欄的信息身隐。這是一個跨頁面的狀態(tài)通信廷区。點擊詳細頁面按鈕的事件代碼如下:
openInfoPage = () => {
//如果未選中一條表格欄,彈窗警告
if (!this.state.selectedItem) {
Modal.info({
title: '信息',
content: '請先選擇一條訂單'
})
return;
}
//將選中的表格欄信息傳入Redux的store狀態(tài)中
this.props.dispatch(orderSelect(this.state.selectedItem))
//設置路由贾铝,跳轉(zhuǎn)新頁面--(默認打開新窗口躲因;傳入?yún)?shù)'_self'則會在本頁面打開新頁面早敬,此過程只是單存的路由跳轉(zhuǎn))
window.open(`/#/order/detail/${this.state.selectedItem.id}`,'_self')
}
在實際操作中,若給新打開的頁面?zhèn)魅胍粋€'_self'參數(shù)大脉,新頁面是在目前的頁面打開搞监,很幸運,他能完成既定的目標镰矿。
但若是傳入?yún)?shù)'_blank'或者不傳參琐驴,則會單獨打開一個新頁面。很不幸的是秤标,新頁面顯示的是store狀態(tài)的初始值绝淡。
分析
造成這個現(xiàn)象的原因是:
_self 只是單純的路由跳轉(zhuǎn),更換一個新的組件(該組件是整個頁面)顯示在目前頁面上苍姜,此過程并沒有刷新頁面牢酵。
_blank(默認值)是重新打開一個新的頁面,每單獨打開一個新頁面都是涉及到刷新操作的衙猪。
因此可以得出馍乙,刷新頁面會導致store中存儲的state(狀態(tài)值)全部變回初始值。
為了佐證這個想法垫释,我刷新了訂單管理界面丝格,發(fā)現(xiàn)頭部的文字變回“首頁”(首頁是store中該狀態(tài)的初始值)
要解決這個問題,需要學習瀏覽器的緩存機制棵譬。而且Redux中提供了redux-persist來實現(xiàn)狀態(tài)的持久化
redux-persist
H5本地存儲
cookies显蝌、sessionStorage和localStorage解釋及區(qū)別
參考資料,弄懂cookie和webstorage订咸。簡單來說就是:
cookie在瀏覽器請求中每次都會附加請求頭中發(fā)送給服務器曼尊。用戶代理(一般值瀏覽器)所實現(xiàn)的大小最少要到達4096字節(jié)
session:Session用于保存每個用戶的專用信息,變量的值保存在服務器端脏嚷,通過SessionID來區(qū)分不同的客戶涩禀。
localStorage保存數(shù)據(jù)會一直保存沒有過期時間,不會隨瀏覽器發(fā)送給服務器然眼。大小5M或更大
sessionStorage僅當前頁面有效一旦關閉就會被釋放。也不會隨瀏覽器發(fā)送給服務器葵腹。大小5M或更大高每。
redux-persist初體驗
我的需求是刷新頁面不會導致store里存儲的狀態(tài)值全部丟失被初始化,這些狀態(tài)在這此網(wǎng)站請求(一次session)過程中是持久化存儲的践宴。當明確這些需求后鲸匿,redux-persist真的是一個很簡單的東西,他就是一個在瀏覽器本地持久化存儲狀態(tài)的方案阻肩。
在store.js
中的代碼如下,
import menuReducer from './../reducer/menuReducer'
import orderReducer from './../reducer/orderReducer'
import { createStore,combineReducers } from 'redux'
import { composeWithDevTools } from 'redux-devtools-extension'
import {persistStore, persistReducer} from 'redux-persist';
import hardSet from 'redux-persist/lib/stateReconciler/hardSet';
import storageSession from 'redux-persist/lib/storage/session'
const reducer = combineReducers({
menu: menuReducer,
order: orderReducer
});
const storageConfig = {
key: 'root', // 必須有的
storage: storageSession, // 緩存機制带欢,默認為localStorage
stateReconciler: hardSet, // 查看 'Merge Process' 部分的具體情況
// whitelist: ['menu','order'] // reducer 里持久化的數(shù)據(jù),除此外均為不持久化數(shù)據(jù)
}
const myPersistReducer = persistReducer(storageConfig, reducer)
const store = createStore(myPersistReducer,composeWithDevTools())
export const persistor = persistStore(store)
export default store
storageConfig
storage的參數(shù)選擇有storageSession和localStorage
- 因為我的需求只是刷新不會導致狀態(tài)丟失运授。storageSession將狀態(tài)值存入內(nèi)存,在關閉所有相關的網(wǎng)頁后乔煞,store存儲的狀態(tài)值才會丟失吁朦、初始化;
- 如果要保持狀態(tài)一直存在渡贾,保存在硬盤上逗宜,下次登錄網(wǎng)頁的時候,狀態(tài)值依然是上次的狀態(tài)值空骚》慕玻可以選擇默認的localStorage(store不傳參即可)。
stateReconciler的參數(shù)有三個選擇囤屹,根據(jù)我的需求選擇hardSet即可
- hardSet (import hardSet from 'redux-persist/lib/stateReconciler/hardSet')直接用將來狀態(tài)替代初始狀態(tài)
- incoming state: { foo: incomingFoo }
- initial state: { foo: initialFoo, bar: initialBar }
- reconciled state: { foo: incomingFoo } // note bar has been dropped
- autoMergeLevel1 (default) 將來狀態(tài)和初始狀態(tài)進行合并熬甚,將來狀態(tài)中的所有成員替換在初始狀態(tài)中的對應成員,其余初始狀態(tài)的成員不變
- incoming state: { foo: incomingFoo }
- initial state: { foo: initialFoo, bar: initialBar }
- reconciled state: { foo: incomingFoo, bar: initialBar } // note incomingFoo overwrites initialFoo
- autoMergeLevel2 (import autoMergeLevel2 from 'redux-persist/lib/stateReconciler/autoMergeLevel2') 和autoMergeLevel1類似肋坚,但是是淺合并(目前還未沒弄清楚淺合并的意義)
- incoming state: { foo: incomingFoo }
- initial state: { foo: initialFoo, bar: initialBar }
- reconciled state: { foo: mergedFoo, bar: initialBar } // note: initialFoo and incomingFoo are shallow merged
最后需要在最頂層的組件中重新設置一下Redux,利用PersistGate包裹根組件乡括。
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import * as serviceWorker from './serviceWorker';
import ERouter from './router'
import { Provider } from 'react-redux'
import store from './redux/store/index'
import {persistor} from './redux/store/index'
import {PersistGate} from 'redux-persist/lib/integration/react';
ReactDOM.render(
<Provider store={store}>
<PersistGate loading={null} persistor={persistor}>
<ERouter />
</PersistGate>
</Provider>,
document.getElementById('root')
)
最后運行效果如下圖所示,圓滿完成既定目標
總結(jié)
匆忙之中冲簿,并未完全掌握粟判,后續(xù)有用到的話,再進一步的深入學習峦剔。