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)
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完成数据过滤,优化数据过滤算法重复执行的问题
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} ] }
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
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)))