dispatching an action returns undefined in callback - reactjs

In my parent component, I have :
getCatalogItems(id = 12, sessionId = "anythingForNow", filterBy = []) {
return this.props.actions.getCatalogInfo(id, sessionId, filterBy)
.then(catalogItemsReturned=> {
console.log("CATALOG ITEMS RETURED", catalogItemsReturned) //always undefined
})
}
componentWillMount() {
console.log("component will mount called")
this.getCatalogItems();
}
render function of this component gets called like 5-6 times for some reason even when I am not changing any state at all.
I pass result from the action to this component as a prop ( I am using redux) through map state to props and the result from this triggered actions becomes available in render function when it calls itself for 3rd or 4th time.
What is the reason? How could I fix it?
My triggered action is getting the result through API call, but for some reason, I am not getting it in then part of dispatch action in getCatalogItems function
This is what my action looks like: Anything wrong with this?
export function getCatalogItemsSuccess(catalogItems) {
return {
type: types.LOAD_CATALOG_SUCCESS,
catalogItems //courses:courses
}
}
export function getCatalogInfo(id = 12, sessionId="anythingForNow", filterBy = []){
return function (dispatch) {
return catalogProductsAPI.getProductsByCategoryId(id, sessionId, filterBy)
.then(
catalogItems =>{
console.log("catalog INFO in actinnnnnnnnnnnnnnnnn", catalogItems) // I get the right results here
dispatch(getCatalogItemsSuccess(catalogItems));
}).catch(err=>{
console.log("errorin get catalog", err);
throw(err);
}); //the function from API would return a promise
};
}

Related

Why does my axios call return undefined even after then is resolved?

I'm currently using functions to predefine all of my axios calls so for example:
export const getClients = () => {
axios.get("/client/")
.then(response=>{
return response;
})
.catch(error=>{
return error;
});
};
Now, I want to call this in a class-based component in the componentDidMount like this:
componentDidMount(){
this.setState({
clients: getClients()
});
}
I can't seem to figure out why when I try to console.log(this.state.clients) at the end of componentDidMount I'm getting an undefined error. I'm new to React and from what I understand, the then in the function of the axios call should resolve the promise and return the actual response from the API call so when I call getClients(), the clients state should be the response.
What am I doing wrong?
componentDidMount(){
fetchClients();
}
const fetchClients = () => {
getClients().then( (response)=> {
// handle success
this.setState({clients:response});
});
};
Okay there is some stuff that needs to be cleared out here :-
You need to change getClients like so :-
export const getClients = () => {
return axios.get("/client/")
.then(response=>{
return response;
})
.catch(error=>{
return error;
});
};
Why ?
Because the value that you returned from the callback of then is wrapped inside a Promise implicitly and has to be returned for consumption as you do in a function like function sum(a,b) {return a+b}
componentDidMount will change like so :-
componentDidMount(){
const fetchClients = async () => {
const clients = await getClients();
this.setState({clients});
}
fetchClients();
}
Why ?
If you want to use getClients in a statement fashion instead of .then().then() promise chain, you will first wrap it inside an async function and then call await on getClients() (remember this function returns a Promise) and then set the state inside that async function.
Even if you console.log the clients state after fetchClients() within componentDidMount, you probably won't see the value set because setState works asynchronously. So never rely on the console.log of your state just after setting it.

Redux fails assigning integer value

In CategoryFeed class, I have something like following:
class CategoryFeed extends Component {
...
componentDidMount() {
const {
params,
currentForum,
updateCurrentForum,
} = this.props;
alert(params.fid);
updateCurrentForum(params.fid);
alert(currentForum);
}
...
export default connect(
(state) => { return {
currentForum: state.app.currentForum,
...
(dispatch) => { return {
updateCurrentForum: (currentForum) => { dispatch(updateCurrentForum(currentForum)); },
...
This is what updateCurrentForum looks like:
export const updateCurrentForum = (currentForum) => {
alert("inside is " + currentForum);
return {
type: UPDATECURRENTFORUM,
payload: currentForum,
};
};
In Reducer, I have defined like:
case UPDATECURRENTFORUM:
return Object.assign({}, state, {
currentForum: action.payload,
});
Here is how it supposed to work from my expectation.
When the CategoryFeed is loaded, it alerts params.fid (let's say params.fid = 1). params.fid is actually additional string after my main url (e.g. if url was http://localhost/1, then params.fid is 1).
Then it stores the value of params.fid (=1) to currentForum via Redux
After I set currentForum by putting payload value to it, then I tried alert the value of currentForum in componentDidMount(). However, it does not show "1" but it shows "undefined". It looks like redux has failed putting params.fid to currentForum.
How can I fix this?
You will not be able to get the updated value of currentForum in componentDidMount(). This is because componentDidMount() only runs once the component is mounted.
Changes to props in componentDidMount() will cause the component to re-render. So the updated value will be accessible in the render() or componentDidUpdate() cycles.
You can move your alert or console.log to the render method and you should see the updated value
componentDidMount will be called after component is inserted into DOM tree and inside that you called updateCurrentForum(params.fid) which will update currentForum but this change will be caught in componentDidUpdate. for more details you can see lifecycle diagram of component http://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/
currently currentForum holds value from
const {
params,
currentForum,
updateCurrentForum,
} = this.props;
which might be undefined currently. try to assign some value in props and see if it changes from undefined to value you provided

Does React batch props updates in some cases?

I'm curious whether React batches updates to props in some rare cases? There is no mention of this in the docs, but I couldn't come up with any other explanation of the following situation.
I have an equivalent to the following code:
// Connected component
class MyComponent extends React.Component {
state = {
shouldDisplayError: false,
};
componentDidUpdate(prevProps) {
console.log("componentDidUpdate: " + this.props.dataState);
if (
prevProps.dataState === "FETCHING" &&
this.props.dataState === "FETCH_FAILED"
) {
this.setState(() => ({ shouldDisplayError: true }));
}
}
render() {
return this.state.shouldDisplayError && <p>Awesome error message!</p>;
}
}
const mapStateToProps = (state) => {
const dataState = getMyDataStateFromState(state);
// dataState can be "NOT_INITIALIZED" (default), "FETCHING", "FETCH_SUCCEEDED" or "FETCH_FAILED"
console.log("mapStateToProps: " + dataState);
return {
dataState,
};
};
export default connect(mapStateToProps)(MyComponent);
// A thunk triggered by a click in another component:
export async const myThunk = () => (dispatch) => {
dispatch({ type: "FETCHING_DATA" });
let result;
try {
result = await API.getData(); // an error thrown immediately inside of here
} catch (error) {
dispatch({ type: "FETCHING_DATA_FAILED" });
return;
}
dispatch({type: "FETCHING_DATA_SUCCEEDED", data: result.data});
}
// Let's say this is the API:
export const API = {
getData: () => {
console.log("> api call here <");
throw "Some error"; // in a real API module, there's a check that would throw in some cases - this is the equivalent for the unhappy path observed
// here would be the fetch call
},
}
What I would expect to see in the console after triggering the API call (which immediately fails), is the following:
mapStateToProps: FETCHING
componentDidUpdate: FETCHING
> api call here <
mapStateToProps: FETCH_FAILED
componentDidUpdate: FETCH_FAILED
However, I can see the following instead:
mapStateToProps: FETCHING
> api call here <
mapStateToProps: FETCH_FAILED
componentDidUpdate: FETCH_FAILED
So the MyComponent component never received the "FETCHING" dataState, although it has been seen in the mapStateToProps function. And thus never displayed the error message. Why? Is it because such fast updates to a component's props are batched by React (like calls to this.setState() in some cases)???
Basically, the question is: If I dispatch two actions, really quickly after each other, triggering a component's props updates, does React batch them, effectively ignoring the first one?
The first time, a component is rendered, componentDidUpdate is NOT called. Instead, componentDidMount is called. Log to console in componentDidMount as well to see the message.

React Native AsyncStorage: Cannot resolve promise returned by getItem

I have the following code that should return an item from AsyncStorage.
However the item is never read:
const key = 'shoppingListItems';
export default class ShoppingListService {
static async getItems()
{
let result = await AsyncStorage.getItem(key);
return result;
}
// ...
}
And I use it in a component (screen):
// ...
componentDidMount()
{
alert(JSON.stringify(ShoppingListService.getItems()));
}
// ...
It always shows me a message with:
{"_40":0,"_65":0,"_55":null,"_72":null}
How do i get the data inside AsyncStorage?
async componentDidMount()
{
alert(JSON.stringify(await ShoppingListService.getItems()));
}
I made the componentDidMount function async. I dont know if thats recommended, but this works.

TypeError: Cannot read property 'then' of undefined while making async call

I have been trying to work on application doing server side rendering. But I have been stuck where I am getting error 'Cannot read property 'then' of undefined'. As soon as my request goes to server for rendering the page, I need to load initial state from database and put it in store.But when I try to fetch data from server side I get the above error. Please find my server side code for rendering initial page
if (renderProps) {
const components = renderProps.components;
var componentObj = renderProps.components[2].WrappedComponent;
const fetchData = (componentObj && componentObj.fetchDatas) || (() => Promise.resolve());
const { location, params, history } = renderProps;
const store = createStore(reducers, initialState, applyMiddleware(thunk));
// calling this function which is place inside another component
// I get error at below line stating cannot read property .then of undefined
fetchData({ store, location, params, history })
.then(() => {
const markup= renderToString(
<Provider store={store}>
<RouterContext {...renderProps} />
</Provider>
)
const state = store.getState();
return res.render('index', { markup,initialState:
JSON.stringify(store.getState()) });
// if the current route matched we have renderProps
}).catch((err)=> {
console.log("error",err);
})
}
Please find my code where I defined the function which is getting called
class IndexPage extends React.Component {
componentDidMount () {
this.props.getCoffeeOrders();
}
// call the action creator
static fetchDatas({store}) {
store.dispatch(getCoffeeOrders);
}
render() {
// render code goes here
}
}
Also Please find my action creator which makes a async call in action creator to fetch the data from server
import axios from 'axios';
export const FETCH_COFFEE_ORDERS = 'FETCH_COFFEE_ORDERS';
export function getCoffeeOrders() {
//below line is getting printed on console
console.log("getting coffee orders inside");
return ((dispatch,getState) => {
// below line is not getting printed
// I think control does not come here
console.log("mKe a call");
return axios.get('http://localhost:8080/api/fetchcoffeeData').then((response)=> {
console.log("got response", response);
dispatch({
type: FETCH_COFFEE_ORDERS,
data
});
})
.catch((err) => {
console.log("got error while fetching data",err);
});
});
}
Control does not comes to the line which I printed in getCoffeeOrders inside another function.
Any help would be appreciated. Thanks in advance
You don't return the promise in fetchDatas static function it should be something like this:
static fetchDatas({store}) {
return store.dispatch(getCoffeeOrders);
}
But I'm still not sure if redux dispatch returns anything take a look at this github issue

Resources