Dealing with the Redux Saga results in a call invocation

I am new to Redux Saga coming from Redux Thunk. In some situations, I need to know if the API call did not call or failed from within the view from which I called the action. With Redux Thunk, I would do something like the following.

My component and action creator will look like this:

class MyComponent extends Component {

  componentDidMount() {
    this.props.actions.fetchItems()
    .then(result => {
        if (result.status === 'OK') {
            console.log('Request succeeded, take particular action in this view')
        }
        else {
            console.log('Request failed, take other action in this view')
        }
    })
  }

  render() {
    return (
        <div>My view</div>
    )
  }
}


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

const mapDispatchToProps = dispatch => {
    return {
        actions: bindActionCreators({
            ...actions,
        }, dispatch),
    }
}


export default connect(
    mapStateToProps,
    mapDispatchToProps,
)(MyComponent)



import * as t from './actionTypes'
import {CALL_API} from '../api'

const xhrGetItems = (params) => (dispatch, getState) => {
    const action = {
        [CALL_API]: {
            type: t.XHR_ITEMS_FETCH,
            endpoint: `http://www.example.com/myendpoint`,
            method: 'get',
        }
    }
    return dispatch(action)
}

      

My API middleware catches all actions using a property CALL_API

, uses the ajax library to make the appropriate call, and then returns a fulfilled promise. My reducer is configured to handle each of the possible states of the api call (success, failure, pending). All the while, I can still check the result of the call in my view where it came from.

So my question is, how can this be done with Redux Saga? Right now my saga api middleware does everything it should, but when I call fetchItems()

, in my opinion, the result is a simple JS object, so I cannot check if it succeeded.

I may be wrong too. Any suggestions are greatly appreciated.

+3


source to share


1 answer


The common pattern with redux and the redux saga is to create 3 actions to call the API. In your case, I would create:

  • LIST_ITEMS_START
  • LIST_ITEMS_SUCCEEDED
  • LIST_ITEMS_FAILED

Your saga will look something like this:

function* watchListItemsStart() {
  yield takeLatest(LIST_ITEMS_START, listItemsStartFlow)
}

function* listItemsStartFlow() {
  try {
    const result = yield call(api.getItems)

    if (result.status === 'OK') {
      yield put(LIST_ITEMS_SUCCEEDED, items)
    } else {
      throw new Error(result.error)
    }
  } catch (error) {
    yield put(LIST_ITEMS_FAILED, error)
  }
}

      

The sagas have completely abstracted the API side effect. The reducer can focus on government management:



switch (action.type) {
  case LIST_ITEMS_START:
    return {
      ...state,
      isLoading: true,
      error: null,
      items: [],
    }
  case LIST_ITEMS_SUCCEEDED:
    return {
      ...state,
      isLoading: false,
      items: action.payload.items,
    }
  case LIST_ITEMS_FAILED:
    return {
      ...state,
      isLoading: false,
      error: action.payload.error.getMessage(),
    }
}

      

You now have everything you need in your store that you can select and react to in a component.

class MyComponent extends Component {
  componentDidMount() {
    this.props.fetchItems()
  }

  render() {
    const { isLoading, items, error } = this.props

    // Here you can react to the different states.

    return (
      <div>My view</div>
    )
  }
}

connect(state => ({
  isLoading: itemsSelectors.isLoading(state),
  items: itemsSelectors.getItems(state),
  error: itemsSelectors.getError(state),
}), {
  fetchItems: actions.fetchItems
})(MyComponent)

      

The important point here is that your component is getting very silly. It just gets the props and doesn't process the result of the API call (here promise.then

).

I hope this answer helps you.

+2


source







All Articles