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://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.