<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
最近學習了redux以及react-redux的結合使用確實讓redux在react中更好的輸出程式碼啦~
但是考慮到專案的各種需求,我們還是需要對redux進行深一步的改造,讓其能更好的滿足我們的日常開發,大大提高我們的開發效率。
今天給大家推薦兩個好用的功能包,並解決一個它們結合使用存在的問題。
redux-persist 主要用於幫助我們實現redux的狀態持久化
所謂狀態持久化就是將狀態與本地儲存聯絡起來,達到重新整理或者關閉重新開啟後依然能得到儲存的狀態。
yarn add redux-persist // 或者 npm i redux-persist
Github 地址 https://github.com/rt2zz/redux-persist
大家可以去看看官方的說明檔案,這裡就不一一介紹功能了,簡單講一點常用功能和匯入到專案使用。
帶有 // ** 標識註釋的就是需要安裝後新增進去使用的一些設定,大家好好對比下投擲哦
下面檔案也是一樣
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',// 儲存的標識名 storage, // 儲存方式 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 }
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的狀態就會進行持久化處理了
import { DECREMENT } from './constant' const defaultState = ({ count: 1000, title: 'redux 持久化測試' }) 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
這樣就可以使用起來了,更多的設定可以看看上面Github的地址上的說明檔案
immutable 主要配合我們redux的狀態來使用,因為reducer必須保證是一個純函數,所以我們當狀態中有參照型別的值時我們可能進行淺拷貝來處理,或者遇到深層次的參照型別巢狀時我們採用深拷貝來處理。
但是我們會覺得這樣的處理確實稍微麻煩,而且我們若是採用簡單的深拷貝 JSON.parse JSON.stringify 來處理也是不靠譜的,存在缺陷 就比如屬性值為undefined 時會忽略該屬性。
所以 immutable 就是來幫我們解決這些問題,使用它修改後會到的一個新的參照地址,且它並不是完全複製的,它會盡可能的利用到未修改的參照地址來進行復用,比起傳統的深拷貝效能確實好很多。
這裡就不多說了,想要了解更多可以看看下面的GitHub官網說明檔案。
npm install immutable // 或者 yarn add immutable
GitHub地址 https://github.com/immutable-js/immutable-js
import { INCREMENT } from './constant' import { Map } from 'immutable' // 簡單的結構用Map就行 複雜使用fromJs 讀取和設定都可以getIn setIn ... const defaultState = Map({ // ** count: 0, title: '計算求和案例' }) 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
讀取和派發如下 : 派發無需變化,就是取值時需要get
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)) }
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()()建立並暴露一個Count的容器元件 export default connect( state => ({ count: state.countReducer.get('count'), title: state.countReducer.get('title') }), { incrementAdd: incrementAction, incrementAsyncAdd: incrementAsyncAction } )(RedexTest)
這樣就可以使用起來了,更多的設定可以看看上面Github的地址上的說明檔案
結合使用有一個坑!!!
是這樣的,當我們使用了redux-persist 它會每次對我們的狀態儲存到本地並返回給我們,但是如果使用了immutable進行處理,把預設狀態改成一種它內部客製化Map結構,此時我們再傳給 redux-persist,它倒是不挑食能解析,但是它返回的結構變了,不再是之前那個Map結構了而是普通的物件,所以此時我們再在reducer操作它時就報錯了
如下案例:
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;
import { DECREMENT } from './constant' import { fromJS } from 'immutable' const defaultState = fromJS({ count: 1000, title: 'redux 持久化測試' }) 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
按理說是正常顯示,但是呢由於該reducer是被redux-persist處理的,所以呢就報錯了
報錯提示我們沒有這個 get 方法了,即表示變成了普通物件
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;
import { DECREMENT } from './constant' import { fromJS } from 'immutable' const defaultState = ({ // ** count: 1000, title: 'redux 持久化測試' }) 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 處理每次會返回普通物件,所以我們只能等要在reducer中處理狀態時,我們先將其用immutable處理成它內部客製化Map結構,然後我們再進行set操作修改,最後我們又將Map結構轉換為普通物件輸出,這樣就完美的解決了這個問題。
以上就是redux持久化之redux-persist結合immutable使用問題的詳細內容,更多關於redux持久化redux-persist的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45