React学习之Redux中间件redux-thunk及redux-saga

Redux中间件及异步操作

中间件的概念

如果要添加redux的异步功能,你会在哪个环境添加?

(1)Reducer:纯函数,只承担计算 State 的功能,不合适承担其他功能,也承担不了,因为理论上,纯函数不能进行读写操作。

(2)View:与 State 一一对应,可以看作 State 的视觉层,也不合适承担其他功能。

(3)Action:存放数据的对象,即消息的载体,只能被别人操作,自己不能进行任何操作。

只有发送 Action 的这个步骤,即store.dispatch()方法,可以添加功能。

中间件就是一个函数,对store.dispatch方法进行了改造,在发出 Action 和执行 Reducer 这两步之间,添加了其他功能。

中间件 redux-thunk

store.dispatch方法正常情况下,参数只能是对象,不能是函数。

这时,就要使用中间件redux-thunk

因此,异步操作的第一种解决方案就是,写出一个返回函数的 Action Creator,然后使用redux-thunk中间件改造store.dispatch

import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import reducer from './reducers';

// Note: this API requires redux@>=3.1.0
const store = createStore(
  reducer,
  applyMiddleware(thunk)
);

使用redux和react-thunk进行异步操作

1. 安装应用

安装redux、react-redux、react-thunk以及axios

yarn add redux react-redux react-thunk axios

2. axios配置

utils/axios中配置如下:

import axios from 'axios'

axios.defaults.baseURL = 'https://api-hmugo-web.itheima.net/api/public/v1'

// 请求拦截器
axios.interceptors.request.use(function (config) { 
// Do something before request is sent 
  return config; 
}, function (error) { 
// Do something with request error 
  return Promise.reject(error); 
});
// 响应拦截器
axios.interceptors.response.use(function (response) {
  if(response.status===200){
    return response.data;
  }
  return response;
}, function (error) {
// Do something with response error
  return Promise.reject(error);
});

export default axios;
3. 封装actionType

文件store/actionType/index.js

export const TODO_SYNC = 'TODO_SYNC'
4. 创建actionCreator

文件store/actionCreator/index.js

import { TODO_SYNC } from '../actionType';
import axios from '../../utils/axios'

export const receiveTodos = res=>{
  return {
    type: TODO_SYNC,
    res
  }
}

export const getTodos = ()=>{
  return dispatch =>{
    return axios.get('/home/swiperdata')
      .then(res=>{
        if(res.meta.status===200){
          dispatch(receiveTodos(res.message))
        }
      })
      .catch(err=>{
        console.log(err);
      })
  }
}
5. 创建reducer

文件store/reducer/index.js

import { TODO_SYNC } from '../actionType';

const defaultState = {
  msg: 'hello react'
}

export default (state=defaultState,action)=>{
  switch (action.type) {
    case TODO_SYNC:
      return {
        ...state,
        res:action.res
      }
    default:
      return state;
  }
}
6. 创建store

文件store/index.js

import { createStore,applyMiddleware } from 'redux'
import reducer from './reducer'
import thunk from 'redux-thunk'

const store = createStore(reducer,applyMiddleware(thunk));
export default store;
7. 使用react-redux

项目入口文件src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import { Provider } from 'react-redux'
import store from './store'

ReactDOM.render(
  <Provider store={store}>
    <React.StrictMode>
      <App />
    </React.StrictMode>
  </Provider>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();
8. 组件中发送异步请求

文件components/Test1.jsx

import React,{Component} from 'react'
import { connect } from 'react-redux'
import { getTodos } from '../store/actionCreator'
import store from '../store'

class Test1 extends Component{

  componentDidMount(){
    // store.dispatch(getTodos())
  }
  
  render(){
    let {msg,getMsg,res} = this.props;
    res = res?res:[];
    return (
      <div>
        {msg}
        <button onClick={getMsg}>发送请求</button>
        <ul>
          {
            res.map(v=>(
              <li key={v.goods_id}>
                <img src={v.image_src} alt=""/>
              </li>
            ))
          }
        </ul>
      </div>
    )
  }
}



const mapStateToProps = (state, ownProps) => {
  return {
    msg: state.msg,
    res: state.res
  }
}

// const mapDispatchToProps = (dispatch, ownProps) => {
//   return {
//     getMsg: ()=>{
//       dispatch(getTodos())
//     }
//   }
// }
const mapDispatchToProps = {
  getMsg: ()=>getTodos()
}

export default connect(mapStateToProps,mapDispatchToProps)(Test1)

中间件 redux-saga

使用generator函数在sagas文件中处理业务逻辑,有了redux-saga之后,除了reducer可以接收action,sagas也可以接收并做业务逻辑处理。

  • put

    put这个Effect方法跟redux原始的dispatch相似,都是可以发出action,且发出的action都会被reducer监听到。

    yield put({
       type: GET_MSG_SUCCESS,
       res
    })
    
  • takeEvery和takeLatest

    takeEvery和takeLatest用于监听相应的动作并执行相应的方法。

    takeEvery可以同时监听到多个相同的action。

    与takeEvery不同的是,takeLatest是会监听执行最近的那个被触发的action。

    takeEvery('login',loginFunc)
    
    takeLatest('login',loginFunc)
    

redux-saga安装与使用

1. 安装

yarn add redux-saga

2. 使用

store/actionType.js

export const GET_MSG_SUCCESS = 'GET_MSG_SUCCESS'
export const GET_MSG_START = 'GET_MSG_START'

store/reducer.js

import {GET_MSG_SUCCESS} from './actionType'

const defaultState = {
  msg: 'hello saga'
}
export default (state=defaultState,action)=>{
  if(action.type===GET_MSG_SUCCESS){
    return {
      ...state,
      res:action.res
    }
  }
  return state;
}

store/sagas.js

import { takeEvery,put } from 'redux-saga/effects'
import {GET_MSG_SUCCESS,GET_MSG_START} from './actionType'
import axios from '../utils/axios'


function* mySaga(){
  yield takeEvery(GET_MSG_START,getMsg)
}

function* getMsg(){
  const res = yield axios.get('/home/swiperdata');
  yield put({
    type: GET_MSG_SUCCESS,
    res
  })
}

export default mySaga;

store/index.js

import { createStore,applyMiddleware } from 'redux'
import reducer from './reducer'
import createSagaMiddleware from 'redux-saga'
import mySagas from './sagas'

const sagaMiddleware = createSagaMiddleware()

const store = createStore(reducer,applyMiddleware(sagaMiddleware))

sagaMiddleware.run(mySagas)

export default store

src/index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';
import store from './store'
import {Provider} from 'react-redux';

ReactDOM.render(
  <Provider store={store}>
    {/* <React.StrictMode> */}
      <App />
    {/* </React.StrictMode> */}
  </Provider>,
  document.getElementById('root')
);

// If you want your app to work offline and load faster, you can change
// unregister() to register() below. Note this comes with some pitfalls.
// Learn more about service workers: https://bit.ly/CRA-PWA
serviceWorker.unregister();

components/Test1.jsx

import React, { Component } from 'react';
import { connect } from 'react-redux';
import { GET_MSG_START } from '../store/actionType'

class Test1 extends Component {

  componentDidMount(){
    const { dispatch } = this.props;
    dispatch({type:GET_MSG_START})
  }

  render() {
    const {msg,res} = this.props;
    console.log(res,'__res');
    return (
      <div>
        {msg}
      </div>
    );
  }
}
const mapStateToProps = (state, ownProps) => {
  return {
    msg: state.msg,
    res: state.res
  }
}

export default connect(mapStateToProps)(Test1);
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

King_960725

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值