react-redux的原理

  • 在上一篇博客中以及介绍了react-redux的基本使用,由此可以得出,react-redux中提供的两个API,Provider只不过是组件间通信context方案的应用罢了,用于方便容器组件拿到全局的store; 而另一个connect其实也就是一个高阶组件(HOC hight order component),与路由中的withRouter是很相似的,下面我们就用代码来实现一下connect高阶组件

高阶组件的构建代码如下:

/* ------------ connect(高阶组件) -------------- */
// 这里我们以 404NotFound 组件为实现案例

import React,{useEffect} from 'react'

function NotFound(props) {
// 组件一挂载获取高阶组件生成的组件数据
useEffect(()=>{
console.log('我自己设置的connect高阶组件的数据:',props);
},[])
return (
<div>404 not Found!!!</div>
)
}

// 设置我们自己的connect高阶组件(携带两个参数均为方法)
/*
stateProps: 获取数据
dispatchMethods: 获取方法
*/
function myConnect(stateProps,dispatchMethods){
var state = stateProps() // 运行形参函数获取数据
var dispatch = dispatchMethods() // 运行形参函数获取方法
// 接收一个组件 , 返回一个我升级后的组件
return (MyComponent)=>{
// 接收旧组件后返沪一个新的组件(函数式组件或类组件)
return (props)=>{// 返回一个函数式组件
return (
// 升级后的组件,带红色字体
<div style={{color:'red'}}>
{/* 通过props方法将,路由跳转方法,状态数据,dispatch方法等传给新生成的组件 */}
<MyComponent {...state} {...props} {...dispatch}/>
</div>
)
}
}
}

// 使用自己设置的高阶组件转化对应组件(404页面)
export default myConnect(()=>{
return { // 传递状态
a:1,
b:2
}
},()=>{
return { // 传递方法
c:()=>{},
d:()=>{}
}
})(NotFound)

结果展示:

image

redux持久化

  • redux-persist官方文档

  • React项目中,我们会使用redux 来进行状态管理。redux和其它状态管理(Vue中的Vuex)技术一样,刷新页面后,数据就会恢复成初始状态。届时我们就可以使用redux的一个插件来实现数据的持久化redux-persist,redux-persist会将reduxstore中的数据自动缓存到浏览器的 localStorage 中,以此来实现数据的持久化。

基本使用:

  1. 安装
npm i redux-persist --save
  1. store.js中配置持久化(前缀[持久化])
// 1. 引入redux
import {applyMiddleware, combineReducers, createStore, compose } from 'redux'

// 2. 引入其他的小Reducer
import pageNameReducer from './reducer/pageNameReducer'//处理关于页面标题的reducer
import isShowBottomReducer from './reducer/isShowBottomReducer'//处理底部区域展示的reducer
import dataReducer from './reducer/dataReducer.js'//处理axios异步请求数据的reducer

// 3. 引入中间件
import ReduxThunk from 'redux-thunk'//引入redux-thunk中间件
import ReduxPromise from 'redux-promise'//引入redux-promise中间件

// 7. [持久化]配置数据的持久化效果
import { persistStore, persistReducer } from 'redux-persist'
// [持久化]导入需要配置的数据源,可以选择,storage,cookie,session等
import storage from 'redux-persist/lib/storage'

// 4. 合并reducer
const reducer = combineReducers({
pageNameReducer,
isShowBottomReducer,
dataReducer
})
/*
由于创建的state是不能直接放到创建的store中的, 需要通过reducer将数据添加到store中,
因此创建store时必须创建reducer;reducer函数的返回值, 会作为store之后存储的state,
只要调用dispatch就会重新执行reducer函数,reducer是一个纯函数,不可以直接修改state,
*/

// [持久化]定义配置的信息(存储到浏览器本地缓存的信息)
const persistConfig = {
key: 'root',// 缓存localStorage键名
storage,
// 设置持久化白名单(只持久化某些数据)和黑名单(不持久化某些数据)
blacklist: ['isShowBottomReducer'],// 黑名单不持久化isShowBottomReducer的数据
whilelist:['dataReducer'],//白名单只持久化dataReducer的数据(小狗图片)
}
// [持久化]传入reducer 根据上面的配置信息将reducer持久化
const persistedReducer = persistReducer(persistConfig, reducer)

// 5. 创建全局store(配置redux开发者工具)
//配置redux开发者工具
const composeEnhancers = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose;

// [持久化]将配置了持久化后的reducer传进去创建全局store
const store = createStore(persistedReducer,composeEnhancers(// composeEnhancers(高级模式,可监视同步与异步)
applyMiddleware(ReduxThunk,ReduxPromise)//并应用中间件
))

// [持久化]生成一个持久化的store
let persistor = persistStore(store)

// 6. [持久化]导出store以及持久化的store
export {store,persistor}
  1. 在根组件(项目入口文件-index.js)中引入并设置持久化网关
/* --------------- react项目入口文件 ---------------- */

import React from 'react'//1.引入react
// import ReactDOM from 'react-dom'//2.引入react-dom //react17
import * as ReactDOM from 'react-dom/client'; // react18

import App from './02-advance/05-redux/home.js' // 引入App父组件
//导入react-redux对象 用于分发数据
import { Provider } from "react-redux"

// [持久化]引入持久化store以及正常的store
import {store,persistor} from './store/index.js';
// [持久化]引入持久化网关
import { PersistGate } from 'redux-persist/integration/react'

// ReactDOM.render( // react17
// <h1>欢迎进入React的世界</h1>,
// // 渲染到哪里(函数式编程)
// document.getElementById('root')
// )

// react 18
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
//包裹节点传递store对象,相当于全局变量(类似context)
<Provider store={store}>
{/* [持久化]使用持久化网关包裹跟组件 */}
<PersistGate loading={null} persistor={persistor}>
<App/>
</PersistGate>
</Provider>

);// 渲染我们自己定义的app组件(直接使用自闭合标签包裹组件名即可,切记组件名一定要大写)

结果展示:

image
image