網(wǎng)站首頁 編程語言 正文
前言
最近學(xué)習(xí)了redux以及react-redux的結(jié)合使用確實(shí)讓redux在react中更好的輸出代碼啦~
但是考慮到項目的各種需求,我們還是需要對redux進(jìn)行深一步的改造,讓其能更好的滿足我們的日常開發(fā),大大提高我們的開發(fā)效率。
今天給大家推薦兩個好用的功能包,并解決一個它們結(jié)合使用存在的問題。
redux-persist
redux-persist 主要用于幫助我們實(shí)現(xiàn)redux的狀態(tài)持久化
所謂狀態(tài)持久化就是將狀態(tài)與本地存儲聯(lián)系起來,達(dá)到刷新或者關(guān)閉重新打開后依然能得到保存的狀態(tài)。
安裝
yarn add redux-persist
// 或者
npm i redux-persist
Github 地址?https://github.com/rt2zz/redux-persist
大家可以去看看官方的說明文檔,這里就不一一介紹功能了,簡單講一點(diǎn)常用功能和導(dǎo)入到項目使用。
使用到項目上
store.js
帶有 // ** 標(biāo)識注釋的就是需要安裝后添加進(jìn)去使用的一些配置,大家好好對比下投擲哦
下面文件也是一樣
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',// 儲存的標(biāo)識名
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
}
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
注意此時的模塊是在白名單之內(nèi),這樣persist_reducer的狀態(tài)就會進(jìn)行持久化處理了
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
immutable 主要配合我們redux的狀態(tài)來使用,因為reducer必須保證是一個純函數(shù),所以我們當(dāng)狀態(tài)中有引用類型的值時我們可能進(jìn)行淺拷貝來處理,或者遇到深層次的引用類型嵌套時我們采用深拷貝來處理。
但是我們會覺得這樣的處理確實(shí)稍微麻煩,而且我們?nèi)羰遣捎煤唵蔚纳羁截?JSON.parse JSON.stringify 來處理也是不靠譜的,存在缺陷 就比如屬性值為undefined 時會忽略該屬性。
所以 immutable 就是來幫我們解決這些問題,使用它修改后會到的一個新的引用地址,且它并不是完全復(fù)制的,它會盡可能的利用到未修改的引用地址來進(jìn)行復(fù)用,比起傳統(tǒng)的深拷貝性能確實(shí)好很多。
這里就不多說了,想要了解更多可以看看下面的GitHub官網(wǎng)說明文檔。
安裝
npm install immutable
// 或者
yarn add immutable
GitHub地址?https://github.com/immutable-js/immutable-js
使用到項目上
count_reducer.js
import { INCREMENT } from './constant'
import { Map } from 'immutable'
// 簡單的結(jié)構(gòu)用Map就行 復(fù)雜使用fromJs 讀取和設(shè)置都可以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
讀取和派發(fā)如下 : 派發(fā)無需變化,就是取值時需要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))
}
類組件
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)建并暴露一個Count的容器組件
export default connect(
state => ({
count: state.countReducer.get('count'),
title: state.countReducer.get('title')
}),
{
incrementAdd: incrementAction,
incrementAsyncAdd: incrementAsyncAction
}
)(RedexTest)
這樣就可以使用起來了,更多的配置可以看看上面Github的地址上的說明文檔
結(jié)合使用存在的問題
結(jié)合使用有一個坑!!!
是這樣的,當(dāng)我們使用了redux-persist 它會每次對我們的狀態(tài)保存到本地并返回給我們,但是如果使用了immutable進(jìn)行處理,把默認(rèn)狀態(tài)改成一種它內(nèi)部定制Map結(jié)構(gòu),此時我們再傳給 redux-persist,它倒是不挑食能解析,但是它返回的結(jié)構(gòu)變了,不再是之前那個Map結(jié)構(gòu)了而是普通的對象,所以此時我們再在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;
persist-reducer.js
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;
persist-reducer.js
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中處理狀態(tài)時,我們先將其用immutable處理成它內(nèi)部定制Map結(jié)構(gòu),然后我們再進(jìn)行set操作修改,最后我們又將Map結(jié)構(gòu)轉(zhuǎn)換為普通對象輸出,這樣就完美的解決了這個問題。
原文鏈接:https://juejin.cn/post/7129045347044687903
相關(guān)推薦
- 2022-09-17 C++中cin的返回值問題_C 語言
- 2022-07-07 Python數(shù)據(jù)分析之?Matplotlib?散點(diǎn)圖繪制_python
- 2022-08-29 .Net?Core靜態(tài)文件資源的使用_實(shí)用技巧
- 2022-11-07 pandas中字典和dataFrame的相互轉(zhuǎn)換_python
- 2022-08-03 基于PyQt5完成pdf轉(zhuǎn)word功能_python
- 2022-06-09 LVGL?PC模擬器安裝步驟詳解_安裝教程
- 2023-01-17 Python中的迭代器與生成器使用及說明_python
- 2022-05-22 prometheus監(jiān)控nginx的實(shí)現(xiàn)_nginx
- 最近更新
-
- window11 系統(tǒng)安裝 yarn
- 超詳細(xì)win安裝深度學(xué)習(xí)環(huán)境2025年最新版(
- Linux 中運(yùn)行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎(chǔ)操作-- 運(yùn)算符,流程控制 Flo
- 1. Int 和Integer 的區(qū)別,Jav
- spring @retryable不生效的一種
- Spring Security之認(rèn)證信息的處理
- Spring Security之認(rèn)證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權(quán)
- redisson分布式鎖中waittime的設(shè)
- maven:解決release錯誤:Artif
- restTemplate使用總結(jié)
- Spring Security之安全異常處理
- MybatisPlus優(yōu)雅實(shí)現(xiàn)加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務(wù)發(fā)現(xiàn)-Nac
- Spring Security之基于HttpR
- Redis 底層數(shù)據(jù)結(jié)構(gòu)-簡單動態(tài)字符串(SD
- arthas操作spring被代理目標(biāo)對象命令
- Spring中的單例模式應(yīng)用詳解
- 聊聊消息隊列,發(fā)送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠(yuǎn)程分支