redux高阶

redux调试工具

定义

Redux DevTools是一个开源项目,是为谷歌浏览器用户打造的一款实用调试插件,主要适用于开发者使用,使用该插件可以有效地对应用程序或者网页的状态进行调试操作,这个插件拥有丰富的设置参数和可视化工具,可以随时查看到触发的action的变化,

使用redux devtools

安装redux devtools浏览器插件

更多工具===>扩展程序===>点击加载已解压的扩展程序

安装redux-devtools-extension模块

cnpm i redux-devtools-extension -S

store/index.js

  • createStore参数
  • 参数一:reducer函数
  • 参数二:devtool调试工具函数
// 引入调试工具   composeWithDevTools是一个函数
import {composeWithDevTools} from 'redux-devtools-extension'

// 创建store仓库
const store = createStore(reducer,composeWithDevTools())

// 导出store
export default  store

react-redux(重点)

安装

cnpm i react-redux -S
  • 提供两个API:
  • Provider组件,放在index.js中,组件包住App组件。
  • connect()高阶组件,放到容器性组件中。

Provider组件引入

// 导出Provider组件
// Provider: store仓库的提供者
import {Provider} from 'react-redux'
// 导入store
import store from './store'
ReactDOM.render(
  <React.StrictMode>
    <HashRouter>
      <Provider store={store}>
      <App />
      </Provider>
    </HashRouter>
  </React.StrictMode>,
  document.getElementById('root')
);

connect函数

  • 作用:连接组件,形成容器型组件。
  • 第一次是方法的调用, 调用该方法时,返回一个函数并接受两个参数。
  • mapStateToProps: 将state数据映射到props属性上,该参数是一个函数 。
  • mapDispatchToProps: 将dispatch方法映射到props属性上,该参数也是一个函数。
  • 第二次是组件的连接 ,即调用返回的函数,将做为组件传参。
  • 返回值: 返回新的组件,新组建称之为:容器型组件
//将派生state数据映射到props属性上,形参state,必须有返回值为一个对象
const mapStateToProps = (state)=>({
    //键名自定义,值为从state中导出各自子模块中的状态数据。
    list:state.order.list,
    info:state.user.info,
})

// 将dispatch方法映射到props属性上,形参dispatch,必须有返回值为一个对象
const mapDispatchToProps = (dispatch)=>({
    changeList:(list)=>dispatch(orderActions.changeList(list)),
    add:(obj)=>dispatch(orderActions.add(obj)),
    del:(index)=>dispatch(orderActions.del(index)),
    changeInfo:(info)=>dispatch(userActions.changeInfo(info)),
})
const ConnectIndex = connect(mapStateToProps,mapDispatchToProps)(Index)
export default  ConnectIndex

容器型组件

import {connect} from 'react-redux'
const ConnectIndex = connect(mapStateToProps,mapDispatchToProps)(Index)
//ConnectIndex为容器型组件
export default  ConnectIndex

展示型组件

import React from 'react'
//函数组件在此时此刻:称之为:展示型组件 ,一般为函数组件。
export default function Order(props) {
    const {list,changeList} = props;
    return (
        <div>
        </div>
    )
}

容器型组件VS展示型组件

容器型组件展示型组件
关注点逻辑[取数据,更新数据]UI的展现
对redux是否感知
读数据从redux的store 中获取从props中获取
写数据发送redux actions调用props的回调
如何创建通过react-redux connect创建函数组件

总结

容器型组件: 一般采用类组件进行声明  
					书写逻辑
					对接react-redux
展示型组件:一般采用函数组件进行声明
					展示数据
					对接props属性

redux高阶(重点)

bindActionCreators

  • bindActionCreators是redux的一个自带函数。
  • 作用:单个或多个ActionCreator转化为dispatch(action)的函数集合形式。开发者不用再手动写dispatch(actionCreator(type)),而是可以直接调用方法,可以实现简化书写,减轻开发的负担。
import {bindActionCreators} from 'redux'
const mapDispatchToProps = (dispatch)=>({
//使用bindActionCreators合并所有的订单子模块中的dispatch,他可以自动将orderActions内所有的方法添加dispatch方法。
    orderActions: bindActionCreators(orderActions,dispatch),
})
import React from 'react'
export default function Order(props) {
    const {list,
        orderActions:{changeList,add,del}//order中触发action所有的方法都在orderActions中。
           } = props;
    return (
        <div>
            <button onClick={()=>changeList([{id:1,name:'包子'}])}>获取订单列表</button>
            <button onClick={()=>add({id:list.length+1,name:'油条'})}>添加</button>
            <hr />
            {list.map((item,index)=>(
                <div key={item.id}>
                    {item.name}
                    <button onClick={()=>del(index)}>删除</button>
                </div>
            ))}
        </div>
    )
}

selectors

  • 用来派生数据。
export const getList = (state)=>state.order.list
export const getFilter = (state) => {
     console.log(111);//这里当不是本页面的数据计算,这里也会执行。
     const { list, filter } = state.order
     return filter === 0 ? list : list.filter(item => item.status == filter)
 }
  • 组件中:
import {getList} from '../store/modules/order'
//将派生的状态映射到props属性上,必须有返回值为一个对象
const mapStateToProps = (state) => {
    return ({
        // 键名自定义,值为状态的值
        list: getList(state),
    })
}

总结:

redux的五大核心: state   reducer  actions   selectors   modules

Reselect

为什么使用reselect

  • redux让数据流通变得规范、状态管理变得可控。通过用react-redux提供的connect函数, mapStateToProps成为视图组件获取state 的唯一途径。
  • 既然mapStateToProps成为组件获取state的唯一途径,那么当我们想要从mapState提供的状态中计算一些需要的数据时,比如计算当前要展示的页面的项目,我们希望展示的页面依赖的list和 filter变化了,才进行重新计算。
  • 每次store.state update后,redux都会调用一次mapStateToProps,不论list和filter 的值是否改变。当我们的app足够大、组件众多时,这里面大量冗余计算的问题就值得重视 了。reselect这个库的目的,就是帮我们把这部分的计算提取到一个函数中。

安装

cnpm i reselect -S

createSelector

  • 参数一:执行的selector方法

  • 参数二:执行selector方法的回调,回调有返回值为派生的数据。

  • 作用:过滤派生的数据,使个页面数据变化只变化某个页面的数据。类似modules

//selectors
 const getList = (state) => state.order.list // 这里则无需暴露
 const getFilter = (state) => state.order.filter
// createSelector是一个函数
import {createSelector} from 'reselect'
// 优化的过滤列表,这里是真正派生的数据
export const getFilterList = createSelector([getList,getFilter],(list,filter)=>{
console.log(11); //这里当不是本页面的数据计算,这里不会执行。
    // 参数list为:执行getList回调的初始值
    // 参数filter为执行getFilter回调的初始值
    return filter === STATUS.ALL ? list : list.filter(item=>item.status===filter)
})

组件:

import {getFilterList} from '../store/modules/order'
const mapStateToProps = (state) => {
    return ({
        //这里的state,依然会给到getList,getFilter。
        list: getFilterList(state),
    })
}

redux中间件

Redux middleware

在 applyMiddleware中,可以使用中间件。

import { applyMiddleware} from 'redux'//使用中间件函数

自己封装中间件

封装检阅action中间件
  • 我们可以检阅每一个流过的action,并挑选出特定类型的 action 进行相应操作,以此来改变 action。
import { applyMiddleware} from 'redux'
// 封装检阅action中间件
const logger = store=>next=>action=>{
    console.log(store);
    console.log('要提交的action为:',action);
    next(action)//这里不写则阻断。
    console.log('提交之后的state状态数据为',store.getState());
}
const store = createStore(reducer,composeWithDevTools(applyMiddleware(logger)))
export default  store
异步错误处理中间件
import {applyMiddleware} from 'redux'
//异常错误中间件 
const error =  store=>next=>action=>{
    try{
        next(action)
    }catch(err){
        console.log('error的错误信息为',err);
    }
}
const store = createStore(reducer,composeWithDevTools(applyMiddleware(error,logger)))
export default  store

redux-logger中间件

1.安装

cnpm i redux-logger -S

2.引入logger

store/index.js
// 引入中间件 
import {logger} from 'redux-logger'
const store = createStore(reducer,composeWithDevTools(applyMiddleware(logger)))
export default  store

redux-thunk(中间异步处理中间)

1.安装

cnpm i redux-thunk -S

2.store/index.js

// 引入异步处理中间件
import thunk from 'redux-thunk'
const store = createStore(reducer,composeWithDevTools(applyMiddleware(thunk,logger)))
export default  store

3.store/modules/user.js

import axios from 'axios'
// 1.声明state
const initialState = {
    info: '', //用户信息
    indexGoods: [{ content: [] }, { content: [] }, { content: [] }, { content: [] }],
}
// 2.封装actionType
const TYPES = {
    "CHANGE_INFO": "CHANGE_INFO",
    "CHANGE_GOODS": "CHANGE_GOODS"
}
// 3.封装actionCreator
export const actions = {
    changeInfo: (info) => ({ type: TYPES.CHANGE_INFO, info }),
    changeGoods: (indexGoods) => ({ type: TYPES.CHANGE_GOODS, indexGoods }),
    requestActions: (dispatch) => {
        // 发起axios请求
        axios.get('/api/getindexgoods').then(res => {
            if (res.data.code === 200) {
                // 接收dispacth方法, 并自调actions.changeGoods
                dispatch(actions.changeGoods(res.data.list))
            }
        })
    }
}
const userReducer = (state = initialState, action) => {
        switch (action.type) {
            case TYPES.CHANGE_INFO:
                return {
                    ...state,
                    info: action.info
                }
                // throw new Error('出错了')
            case TYPES.CHANGE_GOODS:
                return {
                    ...state,
                    indexGoods: action.indexGoods
                }
            default:
                return state
        }
    }
//派生
export const getInfo = (state) => state.user.info
export const getGoodsList = (state) => state.user.indexGoods

4.Index.jsx

import React, { Component } from 'react'
// 导出connect方法
import {connect} from 'react-redux'
// 导入订单子模块的actions
import {actions as orderActions,getList,getFilterList} from '../store/modules/order'
// 导入用户中心子模块的actions
import {actions as userActions,getInfo,getIndexGoods} from '../store/modules/user'
// 引入子组件
import Order from './Order'
import User from './User'
// 导入bindActionCreators
import {bindActionCreators} from 'redux'

 class Index extends Component {
    render() {
const {info,indexGoods,changeInfo,requestGoods} =  this.props
        return (
            <div>
 <User  info={info} indexGoods={indexGoods} changeInfo={changeInfo} requestGoods={requestGoods} />
            </div>
        )
    }
}
//将state数据映射到props属性上
const mapStateToProps = (state)=>({
    info:getInfo(state),
    indexGoods:getIndexGoods(state)
})

// 将dispatch方法映射到props属性上
const mapDispatchToProps = (dispatch)=>({
    requestGoods:()=>userActions.goodsActions(dispatch)
})
const ConnectIndex = connect(mapStateToProps,mapDispatchToProps)(Index)
export default  ConnectIndex

项目目录设计

按照功能划分

Order			#订单模块
	action.js			#actionCreator
  reducer.js		#reducer函数
  Index.js			#容器型组件
  components
  			Order.jsx		#展示型组件
User			#会员中心模块
	action.js			#actionCreator
  reducer.js		#reducer函数
  Index.js			#容器型组件
  components
  			User.jsx		#展示型组件

弊端:造成代码冗余,修改比较困难

按照类型设计

action.js			#actionCreator
reducer.js			#reducer函数
pages	
			Order.jsx			#容器型组件
     User.jsx				#容器型组件
components
			Order.jsx			#展示型组件
      User.jsx				#容器型组件

弊端:修改数据比较困难

ducks设计模式

src
	assets
  		css
      js
      img
      font
	pages			#一级路由
  	Login
    		Login.jsx
				login.css
		Goods
    		Index.jsx			#容器型组件
        component
        			Goods.jsx		#展示型组件 
  views			#二级路由
  store
  		index.js			#store仓库
      modules
      				order.js		#订单子模块[state  | actionCreator | actionType  | reducer | selector]
              user.js			#会员中心子模块[[state  | actionCreator | actionType  | reducer | selector]]
  reuquest
  			http.js
				api.js
  utils
  router
  index.js
	App.jsx
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值