Skip to content

Instantly share code, notes, and snippets.

@hacker0limbo
Created August 24, 2019 10:33
Show Gist options
  • Select an option

  • Save hacker0limbo/b5e72d6aa9fa62e8025a1588981bbdac to your computer and use it in GitHub Desktop.

Select an option

Save hacker0limbo/b5e72d6aa9fa62e8025a1588981bbdac to your computer and use it in GitHub Desktop.
redux 与异步, 关于 redux-thunk 和 redux-promise-middleware 的整理

redux-promise-middleware 与异步

使用 redux-thunk 时候由于一个请求需要写三个 action, 比较麻烦. redux-promise-middleware 可以在根据 type 自动生成对应的 action, 一个例子如下

action 只需写一个基本的, 对应会生成: FETCH_DATA_PENDING, FETCH_DATA_SUCCESS, FETCH_DATA_REJECTED 三种形式

// action

export const getData = () => {
  return {
    type: 'FETCH_DATA',
    // payload 返回了一个 promise
    payload: axios.get('https://test.api')
  }
}

// 三个 action 会自动生成, 只需在 reducer 里处理好即可

reducer 里代码可能为:

const initialState = {
  isLoading: false,
  error: null,
  data: ''
}

const reducer = (state=initialState, action={}) => {
  switch(action.type) {
    case 'FETCH_DATA_FULFILLED':
      return {
        isLoading: false,
        error: null,
        data: action.payload.data.xxx
      }
    case 'FETCH_DATA_PENDING':
      return {
        isLoading: true,
        error: null,
        data: ''
      }
    case 'FETCH_DATA_REJECTED':
      return {
        isLoading: false,
        error: action.payload.message,
        data: ''
      }
    default: 
      return state
  }
}

redux-thunk 与异步

有时候一些 action 需要做一些异步操作, 例如发送 ajax 请求, redux-thunk 可以使得 action 可以返回一个函数而不是一个对象, 类似这样:

// action 如下
export const action1 = () => {
  return dispatch => {
    setTimeout(() => {
      dispatch({
        type: 'xxx'
      })
    }, 2000)
  }
}

export const action2 = () => {
  return dispatch => {
    // 这里 return 不是必须的, fetch 返回一个 promise, 因此可以方便的调用 then
    return fetch('xxxx')
      .then(res => res.json())
      .then(data => {
        dispatch(receiveData(data))
      })
  }
}

发送, 成功, 失败

一般请求有三个步骤:

  • 发送了一个请求(显示一个 Loading 标志)
  • 请求成功(显示对应数据)
  • 请求失败(设置失败信息)

因此对应的, 需要写三个对应的 action 来进行处理, state 以及 reducer 可能如下:

const initialState = {
  isFetching: false,
  error: null,
  data: {}
}

const reducer = (state=initialState, action={}) => {
  switch(action.type) {
    case 'FETCH_REQUEST':
      return {
        isFetching: true,
        error: null,
        data: {}
      }
    case 'FETCH_SUCCESS':
      return {
        isFetching: false,
        error: null,
        data: action.data
      }
    case 'FETCH_FAILURE':
      return {
        isFetching: false,
        error: action.error,
        data: {}
      }
  }
}

虽然 action 需要三个, 但是请求是一个完整的过程, 所以需要一个主 action 来主导完整的请求

// 主 action, 一个完整的请求的 action 在这里集中, 返回的是一个函数
// 该函数可以使用 mapDispatchToProps 传到组件中, 进行数据获取
const getData = () => {
  return dispatch => {
    // 发送请求的 action
    dispatch(fetchRequest())

    axios.get('https://test/api/')
      .then(res => {
        // 发送请求成功的 action
        dispatch(fetchSuccess(res.data))
      }).catch(error => {
        // 发送请求失败的 action
        dispatch(fetchFailure(error.data))
      })
  }
}

const fetchRequest = () => {
  return {
    type: FETCH_REQUEST
  }
}

export const fetchFailure = (error) => {
  return {
    type: FETCH_FAILURE,
    error
  }
}

export const fetchSuccess = data => {
  // user 是个对象
  return {
    type: FETCH_SUCCESS,
    data
  }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment