Redux action not getting called the second time - javascript

I have two redux actions which call as follows.
export function action1(params) {
//This line is always called.
return (dispatch) => {
//This line is not called the second time.
return MyApi.call1(params)
.then(response => {
// some logic
return dispatch(someFunction1());
})
.catch(error => {
throw(error);
});
};
}
export function action2(params) {
return (dispatch) => {
return MyApi.call2(params)
.then(response => {
// call the first API again
action1();
return dispatch(someFunction2());
})
.catch(error => {
throw(error);
});
};
}
When the view is first loaded, action1 is called within the constructor of the view. Upon performing an action and triggering action2 in the same view, action1 needs to be called on action2's success to get the updated list from the server. Unfortunately, code breaks without any error when action1 is called the second time.
What am I missing here?

You have not dispatched the action1.
dispatch( action1( params ) )
Invoking action1() without dispatch just returns a function. In order to get dispatch in returned function, you should dispatch that function. Then it will be caught by redux-thunk middleware. The middleware will pass dispatch and invoke function.

Related

Awaiting for an async action creator to update the state inside another action creator

I have an action creator that performs an async request and updates the state (using react-redux middleware):
export function requestA() {
return function (dispatch) {
dispatch(startRequest())
return Service.getA().then(
data => dispatch(receivedA(data)),
error => console.log("An error occurred.", error)
)
}
}
That works fine.
Now I want to create another action creator, that will use the requestA() action creator, and will call another async request.
export function requestB() {
return function (dispatch, getState) {
dispatch(requestA()) // <--- How to await for this ???
let A_data = getState().A_data;
return Service.getB(A_data).then(
data => dispatch(receivedB(data)),
error => console.log("An error occurred.", error)
)
}
}
Is there a way for me to await for the dispatch(requestA()) to complete before I continue to run the rest of the function?
I need the state to be updated before I continue to the next request.
Note
I know I could do this by calling the 2 requests in my action creator, but I want to know if I can do it calling the dispatch(requestA()) , as the logic for that is already set.
You just need to wait for the call function to finish using await async keywords:
export function requestA() {
return async function (dispatch) {
dispatch(startRequest())
await Service.getA().then(
data => dispatch(receivedA(data)),
error => console.log("An error occurred.", error)
)
}
}

Why is my react/redux function not returning a promise?

I am in my cart actions and I am calling loadCartItems() from another function within the same file. However, this function is not returning a promise or any data and I do not know why. My loadCartItems() function is not even being recongized as a function actually. Does anyone know why this might be?
export function loadCartItems() {
return (dispatch, getState) => {
dispatch({
type: types.LOAD_CART_PRODUCTS
});
return AsyncStorage.getItem(STORAGE_KEY_JWT_TOKEN).then((key) => {
return API.getCartItems(key)
.then((response) => {
return dispatch({
type: types.LOAD_CART_PRODUCTS_SUCCESS,
response
});
}).catch(err => {
console.log('Error retrieving cart products');
})
}).catch(err => {
console.log("Error retrieving cart items from local storage");
});
};
}
export function getUnaddedCartItems() {
return (dispatch, getState) => {
dispatch({
type: types.GET_UNADDED_ITEMS
});
return AsyncStorage.getItem(STORAGE_KEY_CART_ITEMS).then((result) => {
const addedItems = JSON.parse(result);
loadCartItems()
.then((result) => {
const cartItems = result.response.products;
if (this.state.unaddedCartItems.length === 0) {
const unaddedCartItems = addedItems.filter((addedItem) => {
return cartItems.find(cartItem => cartItem.id !== addedItem.productId);
});
}
}).catch(err => {
consoel.log('error: ', err);
});
}).catch(error => {
console.log('error: ', error);
});
};
}
this.loadCartItems() isn't a function. loadCartItems() is.
Since they aren't in a common class/object/something, there is no need to use this. It basically acts like a global (within the context of that file), so just call it directly.
Looking at it a bit closer, it looks like you are trying to call an action creator within an action creator. That's your problem.
Normally, you map these actions within your component, so it takes care of the dispatch bit for you. However, when you are calling the function directly yourself, you need to also deal with it yourself.
loadCartItems().then is the thing that isn't a function now that you've removed the this. That makes sense, since loadCartItems() actually returns a function, not a Promise. The function accepts two arguments: dispatch and getState.
You need to call it like this: loadCartItems()(dispatch, getState).then().
It doesn't actually say loadCartItems() is not a function
It says loadCartItems(...).then is not a function.
What does it mean?
In fact, loadCartItems(...).then is not a function, because the function doesn't return a Promise. It returns another function!
As stated in redux-thunk docs:
Any return value from the inner function will be available as the return value of dispatch itself.
So, in order to properly call your loadCartItems() action, you should do
dispatch(loadCartItems(anyParamYouWant)).then(...)
I'd recommend you to take a look at redux-thunk docs to help you get a better understanding on how thunks works ;)
Both loadItems and getUnaddedCartItems return thunks, not promises.
They therefore need to be dispatched first, so that they return the promises you're expecting.
That dispatch code before you return the promise seems to be unnecessary so if you in fact don't need it, just have the functions return the promises.

react-native - call another function when fetch is over

I'm new to React-Native
I have fetch, through which I get some data. What I want to do is to call another function or update the state, after the request is over and data is ready. Here is my code.
getProducts()
{
return fetch(prodUrl, {method: "GET"})
.then((response) => response.json())
.then((responseData) => {
this.setState({brandList: responseData.products});
console.log("Brands State -> : ",this.state.brandList)
})
.done();
}
I call this getProducts() function in componentWillMount() and trying to use fetched data in render().
After I set the state, I can't see the change when I try to console.log(), most probably because fetch() is async. How can I stop execution of render() function before fetch() is over? Or can you recommend any other request type rather then fetch() which is sync.
It's not because fetch is async, you already have your responseData at that point. It is because setState doesn't change state immediately, so you're console.log is being called before state is being changed. setState has an optional callback as it's second parameter that will be called once set is done being updated, so you can change it like this to see the effect correctly:
getProducts()
{
return fetch(prodUrl, {method: "GET"})
.then((response) => response.json())
.then((responseData) => {
this.setState(
{brandList: responseData.products},
() => console.log("Brands State -> : ",this.state.brandList)
);
});
}
You do not want to "stop" the render() function from being executed. You can, however, apply a check in render if the data is available and render a spinner or something else while it is not.
Very rough sketch of how this could look like:
render() {
let component = this.state.brandList ? <ComponentWithData/> : <Spinner/>;
return component;
}

Infinite loop when dispatching in componentWillMount

I'm working in a React + Redux + redux-thunk codebase and I'm seeing some odd behavior. If I attempt to execute TWO actions in componentWillMount, the second action will infinitely loop.
Here's the componentWillMount:
componentWillMount() {
const { actions } = this.props;
// Action #1 (synchronous)
actions.openLoader();
// Action #2 (promise-based fetch)
actions.getListingsPurchased().then(() => {
actions.closeLoader();
})
.catch(error => {
console.error(error);
});
}
The first action, openLoader() is a simple state update. The second action does a fetch to the server. Action file here:
export function openLoader() {
return {
type: TYPES.SET_LOADER_OPEN
};
}
export function getListingsPurchased() {
return dispatch => {
return fetch'URL GOES HERE', { 'credentials': 'include' })
.then(response => {
return response.json();
})
.then(response => {
return dispatch({ type: TYPES.SET_LISTINGS, data: response.data });
});
};
}
If I was to remove the first action openLoader() from componentWillMount the infinite loop does not happen. Otherwise the fetch call will keep repeating endlessly.
Any help would be appreciated, I seem to have hit a wall.
I believe the best place for breaking infinite loop is in Redux reducer. Reducer is the place where you have to decide if you going to update the state of your app -> will trigger re-render of your components -> will trigger fetch action.
So try to put in place some reducer condition where you can recognize that state was already fetched before and you not going to update the state.

return promise from store after redux thunk dispatch

I am trying to chain dispatches with redux thunk
function simple_action(){
return {type: "SIMPLE_ACTION"}
}
export function async_action(){
return function(dispatch, getState){
return dispatch(simple_action).then(()=>{...});
}
}
How do I get the dispatch to return a promise from the store?
MORE SPECIFICALLY:
I am probably just not understanding something here, but in all the examples with redux-thunk, they call a separate async event (like fetch), which obviously returns a Promise.
What I'm specifically looking for is when I dispatch an action to the store: How do I make certain the store has processed that action completely before anything else happens in the function action_creator() above.
Ideally, I would like the store to return some sort of promise, but I don't understand how or where that happens?
Here you have an example on how to dispatch and chain async action. https://github.com/gaearon/redux-thunk
The thunk middleware knows how to turn thunk async actions into actions, so you just have to have your simple_action() to be a thunk and the thunk middleware will do the job for you, if the middleware see a normal action, he will dispatch this action as normal action but if it's an async function it will turn your async action into normal action.
So your simple_action need to be a thunk ( A thunk is a function that returns a function.) Like this for example:
function makeASandwichWithSecretSauce(forPerson) {
return function (dispatch) {
return fetchSecretSauce().then(
sauce => dispatch(makeASandwich(forPerson, sauce)),
error => dispatch(apologize('The Sandwich Shop', forPerson, error))
);
};
}
When using the makeASandwichWithSecretSauce function you can use the dispatch function
store.dispatch(
makeASandwichWithSecretSauce('Me')
);
And even
// It even takes care to return the thunk’s return value
// from the dispatch, so I can chain Promises as long as I return them.
store.dispatch(
makeASandwichWithSecretSauce('My wife')
).then(() => {
console.log('Done!');
});
Here a complete example on how you can write action creators that dispatch actions and async actions from other action creators, and build your control flow with Promises.
function makeSandwichesForEverybody() {
return function (dispatch, getState) {
if (!getState().sandwiches.isShopOpen) {
// You don’t have to return Promises, but it’s a handy convention
// so the caller can always call .then() on async dispatch result.
return Promise.resolve();
}
//Do this action before starting the next one below
dispatch(simple_action());
// We can dispatch both plain object actions and other thunks,
// which lets us compose the asynchronous actions in a single flow.
return dispatch(
makeASandwichWithSecretSauce('My Grandma')
).then(() =>
Promise.all([
dispatch(makeASandwichWithSecretSauce('Me')),
dispatch(makeASandwichWithSecretSauce('My wife'))
])
).then(() =>
dispatch(makeASandwichWithSecretSauce('Our kids'))
).then(() =>
dispatch(getState().myMoney > 42 ?
withdrawMoney(42) :
apologize('Me', 'The Sandwich Shop')
)
);
};
}
//apologize and withdrawMoney are simple action like this for example
return {
type: "END_SUCESS"
}
//usage
store.dispatch(
makeSandwichesForEverybody()
).then(() =>
console.log("Done !");
);
To create you own promises you can use a library like bluebird.
//EDIT :
To be sure that the store has processed that action completely before anything else happens in the function action_creator() you can dispatch this simple_action before action_creator(); // I added this comment to the code //Do this action before starting the next one below
This is a pattern I've been using recently:
export const someThenableThunk = someData => (dispatch, getState) => Promise.resolve().then(() => {
const { someReducer } = getState();
return dispatch({
type: actionTypes.SOME_ACTION_TYPE,
someData,
});
});
When you dispatch(someThenableThunk('hello-world')), it returns a Promise object that you can chain further actions to.
dispatch will return whatever the action/function it calls returns; so if you want to chain certain activities (as per your example), your action would need to return a Promise.
As #Aaleks mentions, if your action were a thunk you can create a scenario where you return a Promise, then you could do as you mention.
BTW I think naming your thunk action_creator is a bit misleading, as simple_action is actually an Action Creator in Redux parlance - have edited accordingly :)
What you will need to do is create trunkate action which returns Promise. The dispatch function return what you have added as argument to it's call. For example, if you want dispatch to return Promise you'd have to add Promise as argument to the call.
function simple_action() {
return { type: 'SIMPLE_ACTION' };
}
export function async_action(dispatch, getState) {
return function () {
return Promise.resolve(dispatch(simple_action()));
}
}
const boundAction = async_action(dispatch, getState);
boundAction().then(() => {});
Asynchronous action and how to call an action from a component when using redux and thunk
Without Promise
action.js
export function shareForm(id) {
return function (dispatch) {
dispatch({
type: 'SHARE_FORM',
payload: source.shareForm(id)
})
}
}
SomeComponent.js
dispatch(shareForm(id))
With Promise
action.js
export function shareForm(id, dispatch) {
return new Promise((resolve, reject) => {
dispatch({
type: 'SHARE_FORM',
payload: source.shareForm(id)
})
.then(res => resolve(res))
.catch(err => reject(err))
})
}
SomeComponent.js
shareForm(id, dispatch)
.then(res => console.log('log on success', res))
.catch(err => console.log('log on failure', err))
PS: Let me know in comments if you need more explanations

Categories