> 文章列表 > react-8 Redux 状态管理 - 持久化存储 => 进阶:React-Redux()和模块化

react-8 Redux 状态管理 - 持久化存储 => 进阶:React-Redux()和模块化

react-8 Redux 状态管理 - 持久化存储 => 进阶:React-Redux()和模块化

1.redux

redux是独立于react的库,是js状态管理库,提供可预测的状态管理。Vue也可用,但是和react比较搭配 。

2. 什么时候用 redux?

解决:任意:多组件共享状态,

解决:任意:两个组件共享数据

3. 三大原则(API) :::背

安装:

//最新版是配合函数式,我们这是class类组件式:所以装4
npm i redux@4

单一数据源store是共享的,但是是只读的,获取store,store.getState()。

单一数据源, 整个应用的 state 被储存一一个 store 任何组件都可以访问到状态,更容易地将状态持久化到本地存储或远程服务器中。

//单一数据源store数据仓库,只读的
console.log( store.getState() ) 

修改需要 store.dispatch() 触发action,调用纯函数执行修改

修改后需要:监听store中数据的变化, store.subscribe()

State 是只读的, 唯一改变 state 的方法就是触发(派发) actionaction 是一个用于描述已发生事件的普通对象

//State 只读的,想修改需要触发action
store.dispatch({    type: 'DELETE_TODO',    index: 1 
}) //监听store中数据的变化
store.subscribe()

store.dispatch() 触发action,调用纯函数reducer 执行修改

action触发后:需要使用纯函数来执行修改, 为了描述 触发 action 后如何改变 state tree ,你需要编写reducer:reducer 只做一件事情,通过之前的 state 和当前的 action 计算得出新的 state ,因此 reducer 必须是一个纯函数(reducer 不应该写有副作用的代码,比如定时器,ajax 请求).

4. 使用 Redux :

react中没有响应式数据,要自己触发

可以多组件: 触发action 传值,会执行reducer.ts

多组件都可修改,但是值不实时更新,这里都要监听解决:让组件更新,可以获得实时数据

但是监听可能会导致内存泄漏:组件不见了,还在执行,内存泄漏了:取消监听解决

配置:实例化store

store下index.ts

//AAA 原始
//导入createStore
import { createStore } from 'redux'//导入reducer(纯函数)
import reducer from './reducer'//实例化store并导出
export default createStore(reducer)

store下reducer.ts :执行reducer.ts,记得返回新值,共享数据

1.   不要直接修改 state 我们使用  JSON.parse(JSON.stringfy()) { ...state, ...newState } 新建一个 state 副本(拷贝)。不能这样使用 Object.assign(state, { text: action }),因为它会改变第一个参数的值。你必须把第一个参数设置为空对象。你也可以使用 { ...state, ...newState } 达到相同的目的。

2.   在default 情况下返回旧的 state。遇到未知的 action 时,一定要返回旧的 state

var initialState = {count: 0
}
var reducer = (state = initialState, action: any) => {// 深拷贝statevar newstate = JSON.parse(JSON.stringify(state))if (action.type == 'ADD') {newstate.count += action.payload;console.log(newstate);return newstate; //返回新的state} else if (action.type == "SUB") {newstate.count -= action.payload;console.log(newstate);return newstate; //返回新的state} else {return state //返回旧的state(之前的state)}
}export default reducer;

使用:比如详情 和购物车都可以操作count

组件1,详情。组件2,购物车(使用是一样的)

subscribe监听触发实时更新,但是会内存泄漏:解决内存泄漏:组件都需要 取消监听

import React, { Component } from 'react';
import store from '../../../store'
//store.getState() //获取store中的数据
//store.dispatch() //触发action修改store中的数据 
//store.subscribe() //监听store中的数据的变化 //store.getState() 在执行时 默认会自动触发store中的reducer纯函数的执行( reducer纯函数内部务必返回state )
//store.dispatch() 在执行时 会自动触发store中的reducer纯函数的执行( reducer纯函数内部会执行最终的修改, 返回修改后的新state )
class Cate extends Component {unsubscribe:any = 100;componentDidMount() {//监听store中的数据的变化(会造成内存泄漏),记得要取消监听this.unsubscribe = store.subscribe(()=>{this.setState({});console.log('Cate 监听回调');})}componentWillUnmount() {//取消监听this.unsubscribe();}handleClick(){//触发action, 修改redux中的数据store.dispatch( { type:'ADD', payload:1 } )}render() {console.log( store.getState() );return (<div className='cate'><h3>详情页面 - {store.getState().count}</h3><button onClick={()=>{ this.handleClick() }}>添加</button></div>);}
}export default Cate;

5. 数据流 :::背

通过dispach触发action

store调用reducer纯函数

纯函数返回新的state保存在store中

6. react-redux 作用:可以不用导入store,看不见store,也不用subscribe监听了,也没有内存泄漏了,

但是connet结构必须写

安装:

npm i react-redux

根组件上:Provider,store

 store下index.ts


// BBB 添加了:::npm i react-redux
// 导入createStore
import { createStore } from 'redux'// 导入reducer(纯函数):::那边直接导出了,所以对象解构接收
import {reducer} from './reducer'// 实例化store并导出
export default createStore(reducer)

reducer.ts

高阶函数content直接导出:

作用:

content 第一个函数:将属性写入到组件的props中。第二个函数:将方法写入到组件的props中。

content 会让当前座机和store联系起来。

content 会监听store的变化,一旦store中的数据发生改变,当前组件会自动更新  

 content结构

直接调用了 ,这点props记得写下ts

7. 代码模块化

 reducer:combinReducers可以合并reducer

 模块

模块

8. redux 中间件(插件)3个

redux-logger 中间件的使用日志打印

//redux-logger 是一个打印数据操作日志的中间件. 
npm i redux-logger //爆红的话
npm i --save-dev @types/redux-logger

  redux-thunk 中间件使用redux-thunk 允许在 action creator 中返回一个函数, 我们可以在该函数中实现异步操作. (redux只支持同步的action,这个解决)

// redux-thunk 允许在 action creator 中返回一个函数, 我们可以在该函数中实现异步操作. 
// eg:发请求
npm install redux-thunk

 redux-persist 插件的使用: 是一个能实现对 store 持久化的中间件.  持久化存储,自动触发一次。返回了新的newstate,报错。解决:返回旧的newstate

//redux-persist 是一个能实现对 store 持久化的中间件. 
npm i redux-persist 

store下index.ts配置

// store下index.ts配置import { createStore,applyMiddleware } from 'redux'
import logger from 'redux-logger'
import thunk from 'redux-thunk'
// import m1 from './middlewares/m1'
// import m2 from './middlewares/m2'import { persistStore, persistReducer } from 'redux-persist'
// import storage from 'redux-persist/lib/storage/session' // defaults to sessionStorage for web
import storage from 'redux-persist/lib/storage' // defaults to localStorage for web//导入reducer
import {reducer} from './reducer'//对reducer纯函数进行持久化处理
var persistedReducer = persistReducer({key:'redux',storage},reducer)//实例化store实例   ,   applyMiddleware 负责应用中间到store( 每个中间件都会在reducer之前先执行 )
// export var store = createStore(persistedReducer,applyMiddleware(m1,m2,logger))
export var store = createStore(persistedReducer,applyMiddleware(logger,thunk))//对store进行持久化处理
export var persistor = persistStore(store)

// reducer.ts 

// reducer.ts
// combinReducers 可以合并 reducer
import { combineReducers } from 'redux'
// 导入模块化的每个子reducer
import { tasklist_reducer } from './reducer/tasklist'
import { userinfo_reducer } from './reducer/userinfo'// 合并每个子 reducer 成一个根reducer
export var reducer = combineReducers({tasklist: tasklist_reducer,userinfo: userinfo_reducer,
})

 //userinfo.ts文件

//userinfo.ts文件
// 子reducer纯函数,只管理一个{}
export var userinfo_reducer = function (state = {},action:any) {// 深拷贝var newstate = JSON.parse(JSON.stringify(state))if (action.type == 'SAVE_USERINFO') {newstate = action.payload;return newstate} else if(action.type == 'REMOVE_USERINFO'){newstate = {};return newstate} else {return state}
}

根目录index.ts

//根目录index.tsimport React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';//导入store和持久化处理后的store
import {store,persistor} from './store';import {Provider} from 'react-redux'//导入redux-persist提供的PersistGate组件
import { PersistGate } from 'redux-persist/integration/react'const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement
);
root.render(// <React.StrictMode>// Provider 组件通过store属性将store传递给内层的每一个组件<Provider store={store}><PersistGate loading={null} persistor={persistor}><App /></PersistGate></Provider>// </React.StrictMode>
);// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();

 

其中:::redux-thunk 中间件使用redux-thunk 允许在 action creator 中返回一个函数, 我们可以在该函数中实现异步操作. (redux只支持同步的action,不支持函数式,redux-thunk 中间件 解决)

触发异步action。可以发请求了axios,存储数据了redux

项目中组件只负责构建,所以请求不要放在组件中,数据最好存起来,算是性能优化

: 了解:和think一样,但是区别太大,使用麻烦了点
npm i redux-sage

 9.自定义中间件 :::

 

自定义中间件和logger使用是一样的,自己定义不用下载了

//自定义中间件 m1
export default function({dispatch, getState}){return function( next ){return function (action){console.log('中间件1');return next(action)}}
}