Redux解耦合
React项目中使用Redux管理状态数据,导致组件中出现了大量store.method调用方式,让两个不同技术之间的代码的耦合度太高,不利于后期项目的维护
react提供了一个模块:react-redux,转么用于解耦合react组件,redux状态管理模式
Provider: 提供者的意思,提供数据管理桥梁,让redux中的数据可以在react组件中按照固定语法直接使用,避免大量的代码耦合
固定语法:将Provider组件包裹在React应用的根组件外部
import Provider from 'react-redux'
import store './store/index'
function() {
return <Provider store={store}>
其他组件
</Provider>
}
connect() ,用于管理指定的组件,映射数据state和操作方案action
固定语法:将默认组件的导出方式,连接到数据和操作的映射关系上
import {connect} from 'react-redux'
export default connect(映射state数据,映射action函数)(goods)
代码操作
安装react-redux
yarn add react-redux
编辑App.jsx
import {Provider} for 'react-redux'
...
function App() {
return (
<Provider><Goods/></Provider>
)
}
...
import React, { Component} from 'react'
import './layout.css'
import { goodsAddAction,goodsEditAction,goodsDelAction } from './store/modules/actionCreator'
import {connect} from 'react-redux'
import store from './store'
class Layout extends Component {
state={
goodsList:store.getState().goods,
hasId:null,
values: {
name:'',
price:''
}
}
componentDidMount() {
store.subscribe(()=>{
this.setState({})
})
}
changeName=(event)=>{
this.state.values.name = event.target.value
this.setState({
})
}
changePrice=(event)=>{
this.state.values.price = event.target.value
this.setState({
})
}
submit=()=> {
if(this.state.hasId) {
// store.dispatch({type:'edit',data:{...this.state.values,id:this.state.hasId}})
// store.dispatch(goodsEditAction({...this.state.values,id:this.state.hasId}))
this.props.goodsEditAction({...this.state.values,id:this.state.hasId})
}else {
// store.dispatch({type:'add',data:this.state.values})
// store.dispatch(goodsAddAction(this.state.values))
this.props.goodsAddAction(this.state.values)
}
this.state.values.name = ''
this.state.values.price = ''
this.state.hasId = null
this.setState({
goodsList:store.getState().goods
})
}
edit=(item)=>{
console.log(item);
this.state.values.name = item.name
this.state.values.price = item.price
this.state.hasId = item.id
this.setState({})
}
deletGoods=(id)=>{
// store.dispatch({type:'del',data:{id}})
// store.dispatch(goodsDelAction({id}))
this.props.goodsDelAction({id})
this.setState({
goodsList:store.getState().goods
})
}
render() {
return (
<div>
名称:<input type="text" value={this.state.values.name} onChange={(event)=>this.changeName(event)}/>
单价:<input type="text" value={this.state.values.price} onChange={(event)=>this.changePrice(event)}/>
<button onClick={this.submit}>{this.state.hasId?'编辑':'新增'}</button>
{this.state.goodsList.map(item=>
<h2 key={item.id}>
<span>id:{item.id}</span>
<span>商品名:{item.name}</span>
<span>单价:{item.price}</span>
<button onClick={()=>this.edit(item)}>编辑</button>
<button onClick={()=>this.deletGoods(item.id)}>删除</button>
</h2>
)}
</div>
)
}
}
const mapStateToProps = state=>{
return {
goods: state.goods
}
}
const mapActionsToProps = dispatch=> ({
goodsAddAction:goods=>dispatch(goodsAddAction(goods)),
goodsDelAction:goods=>dispatch(goodsDelAction(goods)),
goodsEditAction:goods=>dispatch(goodsEditAction(goods))
})
export default connect(mapStateToProps,mapActionsToProps)(Layout)
1.数据条件过滤
redux是react组件的状态管理模式,负责管理组件中的所有数据,在数据处理过程中也包含根据条件进行数据过滤的行为,如过滤商品中价格超过200商品
1.selectore
自定义数据过滤函数,创建 store/modules/goods/goodsSelector.js
export function goodsByPriceSelector(goodsList,price) {
return goodsList.filter(goods=>goods.price>price)
}
编辑主页,添加条件过滤函数,完成数据过滤
import {goodsSelector} from './goodsSelector'
...
state=this.props.goods
state=this.props.goodsCondition
...
const mapStateToProps = state => {
return {
goods:state.goods,
goods:goodsByPriceSelector(state.goods,200)
}
}
存在的问题,自定义数据条件过滤函数,存在同样的数据在多次访问时重复执行的问题,可以进行性能优化操作
2.reselect
描述:服务于redux数据条件过滤的一个第三方模块
作用:主要用于定义数据条件过滤操作
yarn add reselect
编辑文件 store/modules/goods/goodsSelector.js
import {createSelector} from 'reselect'
export const goodsByPriceSelector= createSelector(function(goodsList){
//第一个参数:是一个函数,用于将传如的数进行预处理
//让数据符合后续的运算条件,如果可以进行格式转化,结构重新设计
return goodsList
},function(dataSource){
//第二个参数,是一个函数,主要用于数据的条件过滤
//参数数据:是第一个函数的返回值
return dataSouce.filter(goods=>goods.price>5000)
})
通过运行结果发现,如果条件过滤数据没有发生变化,reselect中就会直接使用上次缓存的数据结果,而不会再次执行内部的算法进行数据过滤,优化了系统执行性能
数据中如果需要进行数据过滤操作时,就需要考虑这里的数据过滤情况
如果每次数据的过滤条件都基本不一致,可以使用自定义过滤函数,避免了其他模块的引入,降低了编码复杂度的同时优化了模块/数据的加载
如果数据的多次过滤的条件经常出现一致的情况,可以使用第三方模块reselect完成数据过滤,优化数据过滤算法重复执行的问题
2.Action语法优化
1.Action语法优化
通过redux管理组件状态模式之后,所有的数据都被管理起来了,通过ActionCreator完成React组件和状态数据之间的操作关系,封装的actionCreators.js中定义了各种可能的数据操作方式
import {
goodsAddType,goodsEditType,goodsDelType
} from './actionTypes'
export const goodsAddAction = data=>({type:goodsAddType,data})
export const goodsEditAction = data=>({type:goodsEditType,data})
export const goodsDelAction = data=>({type:goodsDelType,data})
需要在React页面组件中引入使用
import {
goodsAddAction,
goodsEditActions,
goodsDelActions
} from './goodsActionsCreator'
存在的语法问题:每增加一种数据的操作方式,就需要做如下两个操作步骤
actionCreators.js中,定义一个新的数据操作方式
React组件Goods.jsx中,通过import再引入新定义的操作方式
React认为上述的操作方式,降低了开发效率,提供了goodsActionCreators用于优化引入操作方式的代码
编辑: Goods.jsx
import * as actions from '../store/moules/goodsActionCreator'
import {bindActionCreators} from 'redux'
const mapActionToprops = dispatch=> bindActionCreators(action,dispatch)
2.Action扩展案例
新增数据初始化Action,编辑 src/store/modules/goodsTypes.js
export const goodsInitType = 'goods/init' //新增一个初始化操作类型
编辑src/store/modules/goodsActionCreators.js
import {
...
brandInitType
} from './goodsTypes'
export const goodsInitAction = data=>({type:goodsInitType,data})
编辑src/store/modules/goodsReducer.js
import {
...
goodsInitType
} from './goodsActionTypes'
function goodsReducer(state=initData,action) {
switch(action.type) {
case goodsInitType:
return action.data
}
}
编辑 Goods.jsx,初始化redux管理的数据
UNSAFE_componentWillMount() {
let axiosData=[
{id:1,name:'小米',price: 2999},
{id:2,name:'OPPO',price: 1999}
]
}
3.redux-devtools
1.redux-devtools
作用:用于配合react应用,完成redux管理的状态的监控
类型:浏览器插件
2.redux-devtools-extension
yarn add redux-devtools-extension
编辑数管理模块:store/index.js 添加调试模块的支持
import {composeWithDevTools} from 'redux-devtools-extension'
const store = createStore
4.异步数据加载
1、React组件中初始化数据
初始化数据由React组件获取
编辑Goods.jsx
UNSAFE_componentWillMount() {
axios.get('url').then(response=>{
if(response.data.code === 200) {
this.props.brandInitAction(response.data.list)
}
})
}
存在的问题:数据管理的职责划分不清楚,导致后期数据部分的维护难以升级
2.Redux管理数据
项目应用中,每个组件的职责划分清除,便于后期项目的维护
React组件:页面视图的渲染,数据更新的请求的发出
Redux组件:数据管理,如初始化、读取、新增、编辑、删除等
编辑goodsActionCreators.js
import axios from 'axios'
import {
goodsAddType,
goodsEditType,
goodsDelType,
goodsInitType
} from './goodsActionTypes'
export const goodsAddAction = data=> ({type:goodsAddType,data})
export const goodsEditAction = data=> ({type:goodsEditType,data})
export const goodsDelAction = data=> ({type:goodsDelType,data})
return dispatch=> {
axios.get("url").then(response=>{
if(response.data.code === 200) {
dispatch(goodsInitAction(response.data.list))
}
})
}
编辑组件Goods.jsx
UNSAFE_componentWillMount(){
this.props.goodsAxiosDataAction() //组件加载时,通知redux需要更新数据
}
注意:如果在actionCreators中添加了自定义函数,发现出现了报错
项目中安装插件 redux-thunk
yarn add redux-thunk
编辑数据管理模块 src/store/index.js,添加中间件支持
import {applyMiddleware} from 'redux'
import thunk from 'redux-thunk'
const store = createStore(combineReducers({
goods:goodsReducer,
order: orderReducer
}),composeWithDevTools(applyMiddleware(thunk)))