美文网首页
redux中间件与异步操作

redux中间件与异步操作

作者: 野蛮生长_ed2e | 来源:发表于2018-05-04 14:01 被阅读0次

    一、中间件的概念

    如果要添加功能,只能在发送Action的时候才可以添加功能,即store.dispatch方法,所以举一个官方的🌰要添加日志功能,吧state和action都打印出来

    let next = store.dispatch;
    store.dispatch = function dispatchAndLog(action) {
      console.log('dispatching', action);
      next(action);
      console.log('next state', store.getState());
    }
    

    以上就是对dispatch的改造,也就是中间件的雏形
    因此中间件就是一个函数,对store.dispatch函数进行改造,在发出action和执行reducer之间,添加其他功能

    二、中间件的用法

    中间件都是现成的,所以我们只要知道如何使用中间件就好

    import { applyMiddleware, createStore } from 'redux';
    import createLogger from 'redux-logger';
    const logger = createLogger();
    
    const store = createStore(
      reducer,
      applyMiddleware(logger)
    );
    

    上面举了一个logger中间件的🌰,redux-logger提供一个生成器createLogger,用来生成日志中间件logger,然后将它放在applyMiddleware方法中传入createstore中
    注意
    (1)createStore方法可以接受整个应用的初始状态作为参数,那样的话,applyMiddleware就是第三个参数了。

    const store = createStore(
      reducer,
      initial_state,
      applyMiddleware(logger)
    );
    

    (2) applyMiddleware方法的三个参数,就是三个中间件。有的中间件有次序要求,使用前要查一下文档。比如,logger就一定要放在最后,否则输出结果会不正确。

    const store = createStore(
      reducer,
      applyMiddleware(thunk, promise, logger)
    );
    

    三、redux-actions

    createAction

    原来创建action:const start = () => ({ type: 'START' })
    现在创建action:import createAction from 'redux-actions'
    const start = createAction('START')

    handleActions

    原来的写法是需要switch或if来匹配

    const todos = (state = defaultState, action) => {
        switch (action.type) {
          case 'ADD_TODO':
            return [
              ...state,
              {
                id: action.id,
                text: action.text,
                str: action.str,
                completed: false
              }
            ]
          case 'TOGGLE_TODO':
            return state.map(todo =>
              (todo.id === action.id)
                ? {...todo, completed: !todo.completed}
                : todo
            )
          default:
            return state
        }
      }
    

    使用redux-actionsreducer操作state:

    const todos  = handleActions({
        ADD_TODO: (state, action) => ({...state,{
                id: action.id,
                text: action.text,
                str: action.str,
                completed: false
              }}),
        TOGGLE_TODO: (state, action) => state.map(todo =>
              (todo.id === action.id)
                ? {...todo, completed: !todo.completed}
                : todo
            )
    }, defaultState)
    

    四、异步处理action

    官网一个🌰

    import fetch from 'cross-fetch'
    
    export const REQUEST_POSTS = 'REQUEST_POSTS'
    function requestPosts(subreddit) {
      return {
        type: REQUEST_POSTS,
        subreddit
      }
    }
    
    export const RECEIVE_POSTS = 'RECEIVE_POSTS'
    function receivePosts(subreddit, json) {
      return {
        type: RECEIVE_POSTS,
        subreddit,
        posts: json.data.children.map(child => child.data),
        receivedAt: Date.now()
      }
    }
    
     export const INVALIDATE_SUBREDDIT = ‘INVALIDATE_SUBREDDIT’
     export function invalidateSubreddit(subreddit) {
       return {
         type: INVALIDATE_SUBREDDIT,
         subreddit
       }
     }
    
    // 来看一下我们写的第一个 thunk action 创建函数!
    // 虽然内部操作不同,你可以像其它 action 创建函数 一样使用它:
    // store.dispatch(fetchPosts('reactjs'))
    
    export function fetchPosts(subreddit) {
    
      // Thunk middleware 知道如何处理函数。
      // 这里把 dispatch 方法通过参数的形式传给函数,
      // 以此来让它自己也能 dispatch action。
    
      return function (dispatch) {
    
        // 首次 dispatch:更新应用的 state 来通知
        // API 请求发起了。
    
        dispatch(requestPosts(subreddit))
    
        // thunk middleware 调用的函数可以有返回值,
        // 它会被当作 dispatch 方法的返回值传递。
    
        // 这个案例中,我们返回一个等待处理的 promise。
        // 这并不是 redux middleware 所必须的,但这对于我们而言很方便。
    
        return fetch(`http://www.subreddit.com/r/${subreddit}.json`)
          .then(
            response => response.json(),
            // 不要使用 catch,因为会捕获
            // 在 dispatch 和渲染中出现的任何错误,
            // 导致 'Unexpected batch number' 错误。
            // https://github.com/facebook/react/issues/6895
             error => console.log('An error occurred.', error)
          )
          .then(json =>
            // 可以多次 dispatch!
            // 这里,使用 API 请求结果来更新应用的 state。
    
            dispatch(receivePosts(subreddit, json))
          )
      }
    }
    

    四、redux-promise中间件

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

    const store = createStore(
    reducer,
    applyMiddleware(promiseMiddleware)
    );

    这个中间件使得接受一个promise对象作为参数,这时,Action Creator 有两种写法。写法一,返回值是一个 Promise 对象。
    ######写法一
    

    const fetchPosts =
    (dispatch, postTitle) => new Promise(function (resolve, reject) {
    dispatch(requestPosts(postTitle));
    return fetch(/some/API/${postTitle}.json)
    .then(response => {
    type: 'FETCH_POSTS',
    payload: response.json()
    });
    });

    ######写法二:**action对象的payload属性是一个promise对象**,这需要从redux-actions模块引入createAction方法
    

    import { createAction } from 'redux-actions';

    class AsyncApp extends Component {
    componentDidMount() {
    const { dispatch, selectedPost } = this.props
    // 发出同步 Action
    dispatch(requestPosts(selectedPost));
    // 发出异步 Action
    dispatch(createAction(
    'FETCH_POSTS',
    fetch(/some/API/${postTitle}.json)
    .then(response => response.json())
    ));
    }

    dispatch方法发出的是异步action,只有等到异步操作结束,这个action才会实际发出,createAction的第二个参数必须是一个promise对象
    
    
    
    

    相关文章

      网友评论

          本文标题:redux中间件与异步操作

          本文链接:https://www.haomeiwen.com/subject/msskrftx.html