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 的方法就是触发(派发) action,action 是一个用于描述已发生事件的普通对象
//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) => {
// 深拷贝state
var 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.ts
import 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)
}
}
}