redux持久化之redux-persist結(jié)合immutable使用問(wèn)題
前言
最近學(xué)習(xí)了redux以及react-redux的結(jié)合使用確實(shí)讓redux在react中更好的輸出代碼啦~
但是考慮到項(xiàng)目的各種需求,我們還是需要對(duì)redux進(jìn)行深一步的改造,讓其能更好的滿足我們的日常開(kāi)發(fā),大大提高我們的開(kāi)發(fā)效率。
今天給大家推薦兩個(gè)好用的功能包,并解決一個(gè)它們結(jié)合使用存在的問(wèn)題。
redux-persist
redux-persist 主要用于幫助我們實(shí)現(xiàn)redux的狀態(tài)持久化
所謂狀態(tài)持久化就是將狀態(tài)與本地存儲(chǔ)聯(lián)系起來(lái),達(dá)到刷新或者關(guān)閉重新打開(kāi)后依然能得到保存的狀態(tài)。
安裝
yarn add redux-persist // 或者 npm i redux-persist
Github 地址 https://github.com/rt2zz/redux-persist
大家可以去看看官方的說(shuō)明文檔,這里就不一一介紹功能了,簡(jiǎn)單講一點(diǎn)常用功能和導(dǎo)入到項(xiàng)目使用。
使用到項(xiàng)目上
store.js
帶有 // ** 標(biāo)識(shí)注釋的就是需要安裝后添加進(jìn)去使用的一些配置,大家好好對(duì)比下投擲哦
下面文件也是一樣
import { createStore, applyMiddleware, compose } from "redux"; import thunk from 'redux-thunk' import { persistStore, persistReducer } from 'redux-persist' // ** import storage from 'redux-persist/lib/storage' // ** import reducer from './reducer' const persistConfig = { // ** key: 'root',// 儲(chǔ)存的標(biāo)識(shí)名 storage, // 儲(chǔ)存方式 whitelist: ['persistReducer'] //白名單 模塊參與緩存 } const persistedReducer = persistReducer(persistConfig, reducer) // ** const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; const store = createStore(persistedReducer, composeEnhancers(applyMiddleware(thunk))) // ** const persistor = persistStore(store) // ** export { // ** store, persistor }
index.js
import React from 'react'; import ReactDOM from 'react-dom/client'; import { Provider } from 'react-redux' import { BrowserRouter } from 'react-router-dom' import { PersistGate } from 'redux-persist/integration/react' // ** import { store, persistor } from './store' // ** import 'antd/dist/antd.min.css'; import './index.css'; import App from './App'; const root = ReactDOM.createRoot(document.getElementById('root')); root.render( <React.StrictMode> <Provider store={store}> {/* 使用PersistGate //** */} <PersistGate loading={null} persistor={persistor}> <BrowserRouter> <App /> </BrowserRouter> </PersistGate> </Provider> </React.StrictMode> );
persist_reducer.js
注意此時(shí)的模塊是在白名單之內(nèi),這樣persist_reducer的狀態(tài)就會(huì)進(jìn)行持久化處理了
import { DECREMENT } from './constant' const defaultState = ({ count: 1000, title: 'redux 持久化測(cè)試' }) const reducer = (preState = defaultState, actions) => { const { type, count } = actions switch (type) { case DECREMENT: return { ...preState, count: preState.count - count * 1 } default: return preState } } export default reducer
這樣就可以使用起來(lái)了,更多的配置可以看看上面Github的地址上的說(shuō)明文檔
immutable
immutable 主要配合我們r(jià)edux的狀態(tài)來(lái)使用,因?yàn)閞educer必須保證是一個(gè)純函數(shù),所以我們當(dāng)狀態(tài)中有引用類(lèi)型的值時(shí)我們可能進(jìn)行淺拷貝來(lái)處理,或者遇到深層次的引用類(lèi)型嵌套時(shí)我們采用深拷貝來(lái)處理。
但是我們會(huì)覺(jué)得這樣的處理確實(shí)稍微麻煩,而且我們?nèi)羰遣捎煤?jiǎn)單的深拷貝 JSON.parse JSON.stringify 來(lái)處理也是不靠譜的,存在缺陷 就比如屬性值為undefined 時(shí)會(huì)忽略該屬性。
所以 immutable 就是來(lái)幫我們解決這些問(wèn)題,使用它修改后會(huì)到的一個(gè)新的引用地址,且它并不是完全復(fù)制的,它會(huì)盡可能的利用到未修改的引用地址來(lái)進(jìn)行復(fù)用,比起傳統(tǒng)的深拷貝性能確實(shí)好很多。
這里就不多說(shuō)了,想要了解更多可以看看下面的GitHub官網(wǎng)說(shuō)明文檔。
安裝
npm install immutable // 或者 yarn add immutable
GitHub地址 https://github.com/immutable-js/immutable-js
使用到項(xiàng)目上
count_reducer.js
import { INCREMENT } from './constant' import { Map } from 'immutable' // 簡(jiǎn)單的結(jié)構(gòu)用Map就行 復(fù)雜使用fromJs 讀取和設(shè)置都可以getIn setIn ... const defaultState = Map({ // ** count: 0, title: '計(jì)算求和案例' }) const reducer = (preState = defaultState, actions) => { const { type, count } = actions switch (type) { case INCREMENT: // return { ...preState, count: preState.count + count * 1 } return preState.set('count', preState.get('count') + count * 1) // ** default: return preState } } export default reducer
讀取和派發(fā)如下 : 派發(fā)無(wú)需變化,就是取值時(shí)需要get
函數(shù)組件
const dispatch = useDispatch() const { count, title } = useSelector(state => ({ count: state.countReducer.get("count"), title: state.countReducer.get("title") }), shallowEqual) const handleAdd = () => { const { value } = inputRef.current dispatch(incrementAction(value)) } const handleAddAsync = () => { const { value } = inputRef.current dispatch(incrementAsyncAction(value, 2000)) }
類(lèi)組件
class RedexTest extends Component { // ....略 render() { const { count, title } = this.props return ( <div> <h2>Redux-test:{title}</h2> <h3>count:{count}</h3> <input type="text" ref={r => this.inputRef = r} /> <button onClick={this.handleAdd}>+++</button> <button onClick={this.handleAddAsync}>asyncAdd</button> </div> ) } } //使用connect()()創(chuàng)建并暴露一個(gè)Count的容器組件 export default connect( state => ({ count: state.countReducer.get('count'), title: state.countReducer.get('title') }), { incrementAdd: incrementAction, incrementAsyncAdd: incrementAsyncAction } )(RedexTest)
這樣就可以使用起來(lái)了,更多的配置可以看看上面Github的地址上的說(shuō)明文檔
結(jié)合使用存在的問(wèn)題
結(jié)合使用有一個(gè)坑?。?!
是這樣的,當(dāng)我們使用了redux-persist 它會(huì)每次對(duì)我們的狀態(tài)保存到本地并返回給我們,但是如果使用了immutable進(jìn)行處理,把默認(rèn)狀態(tài)改成一種它內(nèi)部定制Map結(jié)構(gòu),此時(shí)我們?cè)賯鹘o redux-persist,它倒是不挑食能解析,但是它返回的結(jié)構(gòu)變了,不再是之前那個(gè)Map結(jié)構(gòu)了而是普通的對(duì)象,所以此時(shí)我們?cè)僭趓educer操作它時(shí)就報(bào)錯(cuò)了
如下案例:
組件
import React, { memo } from "react"; import { useDispatch, useSelector, shallowEqual } from "react-redux"; import { incrementAdd } from "../store/persist_action"; const ReduxPersist = memo(() => { const dispatch = useDispatch(); const { count, title } = useSelector( ({ persistReducer }) => ({ count: persistReducer.get("count"), title: persistReducer.get("title"), }), shallowEqual ); return ( <div> <h2>ReduxPersist----{title}</h2> <h3>count:{count}</h3> <button onClick={(e) => dispatch(incrementAdd(10))}>-10</button> </div> ); }); export default ReduxPersist;
persist-reducer.js
import { DECREMENT } from './constant' import { fromJS } from 'immutable' const defaultState = fromJS({ count: 1000, title: 'redux 持久化測(cè)試' }) const reducer = (preState = defaultState, actions) => { const { type, count } = actions switch (type) { case DECREMENT: return preState.set('count', preState.get('count') - count * 1) default: return preState } } export default reducer
按理說(shuō)是正常顯示,但是呢由于該reducer是被redux-persist處理的,所以呢就報(bào)錯(cuò)了
報(bào)錯(cuò)提示我們沒(méi)有這個(gè) get 方法了,即表示變成了普通對(duì)象
解決
組件
import React, { memo } from "react"; import { useDispatch, useSelector, shallowEqual } from "react-redux"; import { incrementAdd } from "../store/persist_action"; const ReduxPersist = memo(() => { const dispatch = useDispatch(); // ** const { count, title } = useSelector( ({ persistReducer: { count, title } }) => ({ count, title, }), shallowEqual ); //const { count, title } = useSelector( // ({ persistReducer }) => ({ // count: persistReducer.get("count"), // title: persistReducer.get("title"), // }), // shallowEqual // ); return ( <div> <h2>ReduxPersist----{title}</h2> <h3>count:{count}</h3> <button onClick={(e) => dispatch(incrementAdd(10))}>-10</button> </div> ); }); export default ReduxPersist;
persist-reducer.js
import { DECREMENT } from './constant' import { fromJS } from 'immutable' const defaultState = ({ // ** count: 1000, title: 'redux 持久化測(cè)試' }) const reducer = (preState = defaultState, actions) => { const { type, count } = actions let mapObj = fromJS(preState) // ** switch (type) { case DECREMENT: // return preState.set('count', preState.get('count') - count * 1) return mapObj.set('count', mapObj.get('count') - count * 1).toJS() // ** default: return preState } } export default reducer
解決思路
由于 redux-persist 處理每次會(huì)返回普通對(duì)象,所以我們只能等要在reducer中處理狀態(tài)時(shí),我們先將其用immutable處理成它內(nèi)部定制Map結(jié)構(gòu),然后我們?cè)龠M(jìn)行set操作修改,最后我們又將Map結(jié)構(gòu)轉(zhuǎn)換為普通對(duì)象輸出,這樣就完美的解決了這個(gè)問(wèn)題。
以上就是redux持久化之redux-persist結(jié)合immutable使用問(wèn)題的詳細(xì)內(nèi)容,更多關(guān)于redux持久化redux-persist的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
React中常見(jiàn)的動(dòng)畫(huà)實(shí)現(xiàn)的幾種方式
本篇文章主要介紹了React中常見(jiàn)的動(dòng)畫(huà)實(shí)現(xiàn)的幾種方式,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-01-01react 頁(yè)面加載完成后自動(dòng)執(zhí)行標(biāo)簽的點(diǎn)擊事件的兩種操作方法
這篇文章主要介紹了react 頁(yè)面加載完成后自動(dòng)執(zhí)行標(biāo)簽的點(diǎn)擊事件,本文給大家分享兩種操作方法結(jié)合示例代碼給大家講解的非常詳細(xì),需要的朋友可以參考下2022-12-12React18系列commit從0實(shí)現(xiàn)源碼解析
這篇文章主要為大家介紹了React18系列commit從0實(shí)現(xiàn)源碼解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-01-01React入門(mén)教程之Hello World以及環(huán)境搭建詳解
Facebook 為了開(kāi)發(fā)一套更好更適合自己的JavaScript MVC 框架,所以產(chǎn)生了react。后來(lái)反響很好,所以于2013年5月開(kāi)源。下面這篇文章主要給大家介紹了關(guān)于React入門(mén)教程之Hello World以及環(huán)境搭建的相關(guān)資料,需要的朋友可以參考借鑒。2017-07-07React中使用Axios發(fā)起POST請(qǐng)求提交文件方式
這篇文章主要介紹了React中使用Axios發(fā)起POST請(qǐng)求提交文件方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-02-02React語(yǔ)法中設(shè)置TS校驗(yàn)規(guī)則的步驟詳解
這篇文章主要給大家介紹了React語(yǔ)法中如何設(shè)置TS校驗(yàn)規(guī)則,文中有詳細(xì)的代碼示例供大家參考,對(duì)大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下2023-10-10基于React實(shí)現(xiàn)無(wú)限滾動(dòng)表格
以文本為例,為了實(shí)現(xiàn)無(wú)限循環(huán)的視覺(jué)效果,我們需要準(zhǔn)備兩段相同的文本,并讓第二段文本的頭部銜接在第一段文本的尾部,同時(shí),為兩段文本設(shè)置相同的滾動(dòng)動(dòng)畫(huà),本文給大家介紹了基于React實(shí)現(xiàn)無(wú)限滾動(dòng)表格,需要的朋友可以參考下2023-11-11