According to the docs, “Without middleware, Redux store only supports synchronous data flow”. I don’t understand why this is the case. Why can’t the container component call the async API, and then dispatch the actions?
For example, imagine a simple UI: a field and a button. When user pushes the button, the field gets populated with data from a remote server.
import * as React from ‘react’;
import * as Redux from ‘redux’;
import { Provider, connect } from ‘react-redux’;
const ActionTypes = {
STARTED_UPDATING: ‘STARTED_UPDATING’,
UPDATED: ‘UPDATED’
};
class AsyncApi {
static getFieldValue() {
const promise = new Promise((resolve) => {
setTimeout(() => {
resolve(Math.floor(Math.random() * 100));
}, 1000);
});
return promise;
}
}
class App extends React.Component {
render() {
return (
{this.props.isWaiting &&
}
);
}
}
App.propTypes = {
dispatch: React.PropTypes.func,
field: React.PropTypes.any,
isWaiting: React.PropTypes.bool
};
const reducer = (state = { field: ‘No data’, isWaiting: false }, action) => {
switch (action.type) {
case ActionTypes.STARTED_UPDATING:
return { …state, isWaiting: true };
case ActionTypes.UPDATED:
return { …state, isWaiting: false, field: action.payload };
default:
return state;
}
};
const store = Redux.createStore(reducer);
const ConnectedApp = connect(
(state) => {
return { …state };
},
(dispatch) => {
return {
update: () => {
dispatch({
type: ActionTypes.STARTED_UPDATING
});
AsyncApi.getFieldValue()
.then(result => dispatch({
type: ActionTypes.UPDATED,
payload: result
}));
}
};
})(App);
export default class extends React.Component {
render() {
return
}
}
When the exported component is rendered, I can click the button and the input is updated correctly.
Note the update function in the connect call. It dispatches an action that tells the App that it is updating, and then performs an async call. After the call finishes, the provided value is dispatched as a payload of another action.
What is wrong with this approach? Why would I want to use Redux Thunk or Redux Promise, as the documentation suggests?
EDIT: I searched the Redux repo for clues, and found that Action Creators were required to be pure functions in the past. For example, here’s a user trying to provide a better explanation for async data flow:
The action creator itself is still a pure function, but the thunk function it returns doesn’t need to be, and it can do our async calls
Action creators are no longer required to be pure. So, thunk/promise middleware was definitely required in the past, but it seems that this is no longer the case?
What\’s wrong with this approach? Why would I use Redux Thunk or redux Promise, according to the documentation?\n\nThis is a big app where there is nothing wrong with this approach.’ It’s just inconvenient because you’ll have different components doing the same things, you may want to debunk some actions or even keep some local defendants, such as auto-incrementing IDs close to action creators so you can read my answer to ‘How to dispatch’ – __USEUSE’, ’ so–to-offoff-to–in order order’.\n\n// // Component component component componentsWillMount() loadData(this.props.dispatch, this. Props .userId); // don\’t forget to pass dispatch.\n\nBut if you write Thunk Middleware like this: // action creator function loadData(userId) return dispatch => fetch(http://data.com/$user Id), // .then (type: \’LOAD_DATA_SUCCESS\’, data ), err _ dispatch([ad__FAILURE] … , i.e.\n\n// component componentWillMount() this.props.dispatch(loadData(this.professoressorId)); // dispatch like you do ().\n\nI don’t think this is the one thing that’s responsible for the dispatching of the ‘pathpath’ response to the request of its creator, ‘‘‘“.’ ‘I’m – ‘Stuffuff’’ is a ‘doo––to–re–meme’ . ‘’It’.’ in response ‘toto’ and ‘retailtails’ to ‘adventive’ [[t] ’‘’–“.“. ‘The response of ‘stress–’,’ on ‘ ‘–t–.–d’ so––e–…–—–i–s–‘–-–o’ “–” ‘the ‘i’ im–n’e’ I’d ‘no ‘tt ‘..d–it’?’ that ‘D’…… ‘“.\n\n// // component componentWillMount() loadAllData(this.props.dispatch, this. PropS.userId); // pass dispatch first .\n\nThe result of other action makers can be dispatched in Redux Thunk action creators, and not even think that those are synchronous or asynchronous: // //Id) =>=> return dispatch (type: \’LOAD_DATADATA_FAILAILURE\’, __TRADERDER DRDRESSESSES((TRAYYERANT TRATRAILILANTANT) PROFOROR STORSTORS HARHARSONSON([TRAD CLASSCLASSESES]] DIRECTDIRECTERER_PROPROSURURURIURID.\n\n// component componentWillMount() this.props.dispatch(loadAllData(this.professoressorId)); // just dispatch normally!\n\nThis approach allows you to use the second getState argument passed to the thunks without modifying the calling code at all: function loadSomeData(userId) //Thanks to Redux Thunk I can use this approach without changing the return of callers (dispatch, getTtate), => i.e. if (getSstate().data[userIDID] – return Promise.resolve()); and then use use of the following approach.\n\nThe following paraphrase: fetch(http://data.com/$userId) .then(res => reS.json()) (type: \’LOAD_SOME_DATA_SUCCESS\’, data ), err (Type: ‘LoAD _____ _______FAILURE’, ERr – ).\n\nSimilarly, if you have to change it to synchronous, you can do this without any calling code: // I can convert it into a normal action creator without touching callers function loadSomeDataME_DATA_SUCCESS return: \’LOAD_SOME\’, data: localStorage.getItem(\’my-data\’) .\n\nHence, the advantage of middleware like Redux Thunk (redux Promise) is that components do not know how to implement action creators, whether they are synchronous or asynchronous, and whether or not they call other action makers.’ The downside is the lack of long-running daemons (“sagas”) that take actions as they come and transform or perform requests before outputting actions. Ultimately, redux thunk and friends are one of the most effective approaches to securing it.\n\nI searched the Redux repo for clues, and found that Action Creators had to be pure functions in the past.\n\nThis is a misunderstanding.’ The docs said this, but were wrong. Action creators were never supposed to be pure functions. We rewritten the DOCs to reflect this.