Redux Thunk Sharing Async Object - reactjs

If I have following thunk:
function postReq(body) {
return dispatch =>
superagent.post("/files")
.then(response => dispatch(actionCreator(response)));
}
How would I share the superagent request object with other parts of my code base? Would I pass it into the actionCreate and put it in the store?
I would like to abort the request on certain Events, that's the reason I am looking for this.
EDIT
To give more context to the Problem on hand. When a user uploads a file he has the option to abort the upload. As I am creating the superagent request within a thunk I need to pass the request object on to be able to call superagent.abort().

Well, first of all I would like to introduce you some ES6 features which would make your code WAY more readable. Right now you have:
function postReq(body) {
return dispatch =>
superagent.post("/files")
.then(response => dispatch(actionCreator(response)));
}
first you could use ES6 to make your function more readable in 2 steps:
Step 1
Update your action creator to be stored at a cost variable:
const postReq = (body) => {
return dispatch =>
superagent.post("/files")
.then(response => dispatch(actionCreator(response)));
}
Step2
Your function is returning a function so you can make it shorter and more readable with an implicit return:
const postReq = (body) => (dispatch) => {
superagent.post("/files")
.then(response => dispatch(actionCreator(response)));
}
Now, answering you could try to do what they expose here:
https://github.com/reactjs/redux/issues/1461#issuecomment-190165193
Which applied to your case would be something like:
const postReq = (body) => (dispatch) => {
superagent.post("/files")
.then(response => dispatch(actionCreator(response)));
const abort = superagent.abort.bind(superagent)
return { abort }
}
I have never done this myself but as far as I understand its binding the abort method to a variable which will be returned and executing the function stored there will call the abort method in the postReq context.

Related

How does a react action have access to dispatch?

In my react project I have an actions file that looks like this:
const startLoad = () => async (dispatch) => {
dispatch({
type: CONTENT_LOAD,
});
};
// Get all content
export const getContents = () => async (dispatch) => {
dispatch(startLoad());
// some more code...
};
So in this example, I know that dispatch is coming from the middleware and getContents has access to it because it was mapped using mapDispatchToProps. So I am assuming when getContents is called, its really called like this -> dispatch(getContents) but can this be replicated in plain JavaScript so I can see what is really going on? If I am wrong about why getContents has access to dispatch please let me know.
For example, how isstartLoad able to use dispatch just because dispatch called startLoad? I have noticed that it will also work if I call it like this: dispatch(startLoad(dispatch));.
Passing dispatch in to startLoad actually makes more sense to me so I don't get why that isn't required.
Edit: this is the closest example I could come up with on my own.
const fun = () => (fun2) => {
fun2();
}
const fun2 = () => {
console.log('hello');
}
fun()(fun2);
So I am assuming when getContents is called, its really called like
this -> dispatch(getContents) but can this be replicated in plain
JavaScript so I can see what is really going on? If I am wrong about
why getContents has access to dispatch please let me know.
redux-thunk has quite simple implementation
function createThunkMiddleware(extraArgument) {
return ({ dispatch, getState }) => (next) => (action) => {
if (typeof action === 'function') {
return action(dispatch, getState, extraArgument);
}
return next(action);
};
}
As you can see it checks if action is a function.
And bonus, if you like you can get the whole state and extra argument in params following dispatch
For example, how isstartLoad able to use dispatch just because
dispatch called startLoad? I have noticed that it will also work if I
call it like this: dispatch(startLoad(dispatch));.
It looks like middleware also handles above case.

Convert array of promises to chain in React

I've seen a number of posts covering similar chaining questions, but I'm trying to understand what I'm specifically missing.
Ultimately, I want to make an API call, then make a second based on the results of the first. To do so, of course, I need to have the results, not just a promise to get them before I make the chained call. I started from an example that does not have the chaining dependency:
export const FetchUserSync = () => {
return Promise.all([
fetchUsers(),
fetchPosts()
]).then(([user, posts]) => {
return { user, posts };
});
function fetchUsers()...
function fetchPosts()...
}
When I call it, the data comes back and state values are set.
useEffect(() => {
dataPromise.then(data => {
setUser(data.user);
setPosts(data.posts);
});
Attempting to change the first code so the second call will wait for the first to complete, I get results in the function (console.log or setting debbugger shows populated objects for user and posts exist), but the useEffect's calling function shows the result to be undefined.
export const FetchUserSync = () => {
return Promise.all([fetchUsers()])
.then(([user]) => {
Promise.all([user, fetchPosts()])
.then(([user, posts]) => {
return { user, posts }
})
});
function fetchUsers()...
function fetchPosts()...
}
Any suggestions on how to make the second idea work or should I just scrap it and go with one of the other answers?
In this case, you wouldn't want to use Promise.all.
Since both fetchUsers and fetchPosts both return promises already, wrapping singular calls with Promises for fetchUser and fetchPosts is an anti-pattern.
Additionally, consider using async/await since they avoid deeply nested chains of data.
Here's what you could do:
export const FetchUserSync = async () => {
const users = await fetchUsers();
const posts = await fetchPosts();
function fetchUsers() { ... }
function fetchPosts() { ... }
return { users, posts }
}
The code will make a request for users, then once users is received, it will make another call for posts.
Consider reading more on async/await: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await

Purpose of Redux Thunk `([arg(s)]) => dispatch =>`?

The code below comes from a Udemy course on the MERN stack by Brad Traversy. I'm new to Redux and Redux Thunk and am trying to understand what the purpose of => dispatch => is. I know it comes from Redux Thunk, which was set up in the Redux store file. I think dispatch is being used here in order to dispatch more than one action from this function and read that the = ([arg(s)]) => dispatch => syntax is an example of currying (though that doesn't seem right since with currying each function has one argument).
I'd greatly appreciate any help understanding => dispatch =>.
(Other minor point of confusion: In the course the function setAlert is referred to as an action, but I'm not sure that's correct since it contains multiple dispatches of actions.)
export const setAlert = (msg, alertType, timeout = 5000) => dispatch => {
const id = uuidv4();
dispatch({
type: SET_ALERT,
payload: { msg, alertType, id }
});
setTimeout(() => dispatch({ type: REMOVE_ALERT, payload: id }), timeout);
};
There's a couple of things going on here:
1) setAlert is what is usually called an "action creator". It's a function that returns an action that you can dispatch later.
2) Redux-Thunk is allowing you to use functions of the form (dispatch) => {} as actions (in place of the more normal object form { type, payload })
It might help if you look at them individually before seeing how they combine together:
// This is an action creator (a function that returns an action)
// This doesn't use redux thunk, the action is just a simple object.
// Because it's an action creator you can pass in arguments
// Because it's not a thunk you can't control when then dispatch happens
const setAlertActionCreator = (msg, alertType) => {
const id = uuidv4();
return {
type: SET_ALERT,
payload: { msg, alertType, id }
};
};
// You use this as:
dispatch(setAlertActionCreator("msg", "type"));
// This is not an action creator it's just an action.
// This IS a redux-thunk action (it's a (dispatch) => {} function not a simple object)
// Because it's not an action creator you can't pass in arguments to get a custom action back
// Because it IS a redux-thunk action you can dispatch more actions later
const setAlertThunk = (dispatch) => {
setTimeout(() => dispatch({
type: SET_ALERT,
payload: {
message: "fixed message",
alertType: "fixed alertType",
id: "fixed id",
}
}), 5000);
};
// You use this as:
dispatch(setAlertThunk);
// When you combine both patterns you gain the ability
// to both pass in arguments and to create additional dispatches
// as the function runs (in this case dispatching again after a timeout.)
// I won't repeat your code, but will show how you would call it:
dispatch(setAlertActionCreator("msg", "type"));
// ie: you use it the same way as example 1.
The syntax () => dispatch => is equivalent to:
function response(){
return function (dispatch){
//Some code here
}
}
So, basically what you can say is, it is a modern way of writing the same function. => dispatch => is returning a function that will be executed when the action will be invoked.
Hope this will help.
=> dispatch =>
is nothing but a syntactical sugar over a function returning another function. Since Fat-arrow functions => are used in place of normal functions.
Like
function abc(a,b){
return a+b;
}
is same as const abc = (a,b) => a+b ;
So you dont have to write return keyword.
So in your case its the same => dispatch => and the one below , its returning an anonymous function with . dispatch as its arguement
function response(){
return (dispatch){
//some code here
}
}
Hope it helps, feel free for doubts

Understanding async dispatch actions using redux thunk

I was just going though the files that dispatches ACTIONS in a reactjs app and basically came across the following function::-
// When app inits
export const init = () => async dispatch => {
dispatch({ type: TYPES.SET_LOADING });
await dispatch(getConfig());
await dispatch(getGenres());
dispatch({ type: TYPES.REMOVE_LOADING });
};
I am a bit confused as to what the async is doing ahead of the dispatch , i am used to seeing normal vanilla javascript async functions like so:
anasyncfunc = async () => {
// write you're code here
}
But the above code confuses me a little. Can somebody please explain this to me.
A function which uses the await keyword must me marked with async which you have pointed out in your example
anasyncfunc = async () => {
// write you're code here
}
In this function we can now use await since it was marked with async.
In the case of the thunk, we are effectively creating an outer function called init which when called will return an anonymous function. This anonymous function will accept dispatch as an argument and will make use of the await keyword, and as such needs to be marked with the async keyword.
In short, we really are just creating a function which will want to use await and therefor must be marked with async.
I hope this clarifies it.

Promises resolved before all inner promise resolved, multiple async API calls

Hi I'm new to the react/redux development environment so I appreciate any help.
I'm trying to make 2 API calls asynchronously when componentDidMount by calling dispatch(fetchAllPositions(selectedUserDivision)) in my app.js
I found a suggested method in this post and the fetchAllPositions function wraps two action functions together in a Promise.all
export function fetchAllPositions(division) {
return dispatch => Promise.all([
dispatch(fetchUserPositionsIfNeeded(division)),
dispatch(fetchDefaultPositionsIfNeeded(division))
])
.then(console.log("fetched both"))
}
The two action functions are nearly identical, they just call a slightly different API url. One of them looks like the follows, where the shouldFetchUserPosition is just a pure function that returns a boolean:
function fetchUserPositions(division) {
return dispatch => {
const url = apiOptions.server + `/api/user/position?division=${division}`
dispatch(requestUserPositions(division))
return fetch(url, options)
.then(response => response.json())
.then(json => dispatch(receiveUserPositions(division,json)),
err => console.log(err))
}
}
export function fetchUserPositionsIfNeeded(division) {
return (dispatch, getState) => {
if (shouldFetchUserPositions(getState(), division)) {
return dispatch(fetchUserPositions(division))
} else {
return Promise.resolve()
}
}
}
The logic is that for an update, a REQUEST... action is sent while pulling data, then a RECEIVE... action is sent when data is ready to be updated into the new state.
The trouble is that the Promise.all should wait for REQUEST1 REQUEST2 RECEIVE1 RECEIVE2 to all come in before doing the .then(console.log("fetched both"))
Right now, it's does the .then after first 2 REQUEST are finished, not waiting for the 2 RECEIVE to come in.
I suspect it's the nested nature of the requestUserPositions() within the function that wraps fetch()
The REQUEST action is a simple function, and in the reducer it just flips an isFetching property to true:
function requestUserPositions(division) {
return {
type: REQUEST_USER_POSITIONS,
division
}
}
Sorry for this long issue but I'd appreciate any suggestions.
This is a careless mistake
Turns out that when the .then() is wrapped inside a dispatch it gets executed simultaneously as the Promise.all() is being carried out.
The intended dispatch order was created by tagging the then(()=>console.log to the last dispatch dispatch(fetchAllPositions(selectedUserDivision)) done from ComponentDidMount

Resources