-
-
Save josefdlange/dd68023971e817432976d15ed1e89261 to your computer and use it in GitHub Desktop.
| // Actions | |
| var startLoadingX = function() { | |
| return { | |
| type: START_LOADING_X // Define this above as you do with Actions. | |
| } | |
| } | |
| var completeLoadingX = function(response, error) { | |
| return { | |
| type: COMPLETE_LOADING_X, // Ditto. | |
| response, | |
| error | |
| } | |
| } | |
| var fetchX = function(possibleParameters) { | |
| return dispatch => { | |
| dispatch(startLoadingX()) | |
| myApiClientIWroteThatReturnsPromisesForApiCalls.getStuff(possibleParameters) | |
| .then(response => dispatch(completeLoadingX(response, null))) | |
| .catch(error => dispatch(completeLoadingX(null, error))) | |
| } | |
| } | |
| // Reducer | |
| const initialState = { | |
| isLoadingX: false, | |
| X: {}, // or [] I suppose, depending on the shape you're expecting your response to have! | |
| errorLoadingX: false, | |
| XErrorData: null | |
| } | |
| export default function myStoresReducer(state = initialState, action) { | |
| switch(action.type) { | |
| case START_LOADING_X: | |
| return Object.assign(state, {}, { | |
| isLoadingX: true, | |
| errorLoadingX: false, | |
| X: {}, // you can decide if you want to clear the actual state on every load. For the sake of UI sometimes it's nice to keep old data there to show anything but a blank component. | |
| XErrorData: null | |
| }) | |
| case COMPLETE_LOADING_X: | |
| if(action.error != null) { | |
| return Object.assign(state, {}, { | |
| isLoadingX: false, | |
| errorLoadingX: true, | |
| X: {}, // Or null or you can leave it alone as discussed above. | |
| XErrorData: action.error | |
| }) | |
| } else { | |
| return Object.assign(state, {}, { | |
| isLoadingX: false, | |
| errorLoadingX: false, | |
| X: state.response, // If your data is embedded in a generic response data structure, this would be a good place to unwrap it, or even in the API client itself. | |
| XErrorData: null | |
| }) | |
| } | |
| } | |
| } | |
Wow, I'm such an idiot. Of course POST requests return the the updated model.
So you would only need one action handler -> that would dispatch a multiple-action thunk function -> which would cause the Redux store to be updated twice?
Once when the reducer catches the initial action, and again when(if) the response returns? But because the data should be identical there would be no change to the user because the React Virtual DOM will not notice any changes?
So for example:
// React Component
incrementValue() {
this.props.dispatch(incrementValueAction(this.props.value + 1)); // value received from store via connect
}
render() {
<button onClick={this.incrementValue.bind(this)}>Increment Value</button>
}
// Action Handler
export default incrementValueAction(value) {
return dispatch => {
dispatch( {type: INC_START, payload: value} )
axios.post("rest/url/", {value: value})
.then(dispatch( {type: INC_COMPLETE, payload: response.data} ))
.catch(...)
}
}
// Reducer
switch (action.type) {
case INC_START:
return {...state, value: action.payload}
case INC_COMPLETE:
return {...state, value: action.payload}
}So then the question becomes, is it really worth having TWO reducer cases that update the Redux state to the same previous state if the RESTful database is always in sync?
You don't even need the first private action (of the two inside the thunk) unless you want to be keeping track of whether or not you are loading --- so that your UI can display that and/or if you want/need to do some cleanup before receiving a potential response.
A well-implemented RESTful API will return the updated model on response, so you'd probably have in your reducer for receiving the response some code to create a new version of the state with an almost exact copy of the prior state -- except the new model data overwriting the old local version in that array. For example: