简体   繁体   中英

Display React Native Redux Saga API response

I have been studying/working with React Native for a couple weeks now, and I'm trying to get a grasp on working with Redux and Redux-Sagas . I have tried researching this for several days now and (thought) I was getting the hang of it, but unfortunately I am still struggling. Here are some resources I have read and attempted:

https://shift.infinite.red/using-redux-saga-to-simplify-your-growing-react-native-codebase-2b8036f650de

https://hackernoon.com/moving-api-requests-to-redux-saga-21780f49cbc8

I am using the Ignite-CLI boilerplate to create an app that queries an API for weather data. The API request works when using the regular api.get() function from apisauce but I can't get the Redux Saga actions to return the data. I'm thinking I just don't understand the concept well enough.

Here is my Api.js file that uses apisauce to fetch the JSON data from the given parameters (this works perfectly)

/App/Services/Api.js

// a library to wrap and simplify api calls
import apisauce from 'apisauce'

// our "constructor"
const create = (baseURL = 'https://my-api-url.com/api/') => {

  const apiId = 'xxxxxxx'
  const apiKey = 'xxxxxxxxxxxxxxxxx'
  const resortKey = 'xxxxxx'
  const apiParams = resortKey + '?app_id=' + apiId + '&app_key=' + apiKey

  const api = apisauce.create({
    // base URL is read from the "constructor"
    baseURL,
    // here are some default headers
    headers: {
      'Cache-Control': 'no-cache'
    },
    // 10 second timeout...
    timeout: 10000
  })

  const getReport = () => api.get(apiParams)

  return {
    getReport,
  }
}

// let's return back our create method as the default.
export default {
  create
}

Ignite CLI has an awesome generator that generates redux actions and sagas automatically. Here are those generated files:

/App/Redux/SnowReportRedux.js (Redux Actions)

import { createReducer, createActions } from 'reduxsauce'
import Immutable from 'seamless-immutable'

/* ------------- Types and Action Creators ------------- */

const { Types, Creators } = createActions({
  snowReportRequest: ['data'],
  snowReportSuccess: ['payload'],
  snowReportFailure: null
})

export const SnowReportTypes = Types
export default Creators

/* ------------- Initial State ------------- */

export const INITIAL_STATE = Immutable({
  data: null,
  fetching: null,
  payload: null,
  error: null
})

/* ------------- Reducers ------------- */

// request the data from an api
export const request = (state, { data }) =>
  state.merge({ fetching: true, data, payload: null })

// successful api lookup
export const success = (state, action) => {
  const { payload } = action
  return state.merge({ fetching: false, error: null, payload })
}

// Something went wrong somewhere.
export const failure = state =>
  state.merge({ fetching: false, error: true, payload: null })

/* ------------- Hookup Reducers To Types ------------- */

export const reducer = createReducer(INITIAL_STATE, {
  [Types.SNOW_REPORT_REQUEST]: request,
  [Types.SNOW_REPORT_SUCCESS]: success,
  [Types.SNOW_REPORT_FAILURE]: failure
})

/App/Sagas/SnowReportSagas.js

import { call, put } from 'redux-saga/effects'
import SnowReportActions from '../Redux/SnowReportRedux'

export function * getSnowReport (api, action) {
  const { data } = action
  // make the call to the api
  const response = yield call(api.getReport, data)

  // success?
  if (response.ok) {
    yield put(SnowReportActions.snowReportSuccess(response.data))
  } else {
    yield put(SnowReportActions.snowReportFailure())
  }
}

Then, following the example they provided, I added the SnowReportActions from SnowReportRedux.js and the getSnowReport function from SnowReportSagas.js to the root saga function as such:

//...imports & constants

export default function * root () {
  yield all([
    // some sagas only receive an action
    takeLatest(StartupTypes.STARTUP, startup),

    // some sagas receive extra parameters in addition to an action
    takeLatest(SnowReportTypes.SNOW_REPORT_REQUEST, getSnowReport, api)
  ])
}

Now here is where I get confused; How do I actually call those dispatch actions within my components or screens? I understand I have to import SnowReport Actions from '../Redux/SnowReportRedux and mapDispatchToProps but I can't get the dispatch to fire... Here are some pieces from one of my screens:

/App/Containers/ResortReportScreen.js

//.. constructor

componentDidMount () {
  this.props.getSnowReport();
}

// .. render() / close component

const mapDispatchToProps = (dispatch) => {
  return {
    getSnowReport: () => dispatch({ type: SnowReportActions.snowReportRequest() })
  }
}

export default connect(null, mapDispatchToProps)(ResortReportScreen)

When the componentDidMount () function fires it should dispatch the SnowReportActions.snowReportRequest() action, right? Whenever I use console.log() to return the response of that action it doesn't end up firing. What am I doing wrong here? How can I get the data from my API request to display when using actions ?

My sagaMiddleware and reducers are all generated automatically by Ignite. If it is necessary to show those just ask.

The function SnowReportActions.snowReportRequest() is an action creator which return an action you have to dispatch. You can fix your code like that :

const mapDispatchToProps = (dispatch) => {
  return {
    getSnowReport: () => dispatch(SnowReportActions.snowReportRequest())
  }
}

You can even simplify your code using an object instead of a method for mapDispatchToProps ( https://github.com/reactjs/react-redux/blob/master/docs/api.md )

const mapDispatchToProps = {
    getSnowReport: SnowReportActions.snowReportRequest
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM