Throwing a SubmissionError of redux-form causes Uncaught (in promise) - javascript

I apologize in advance for the formatting (still a newb on this), and maybe for the stupid question (still a newb on this whole React ecosystem).
I've recently picked up redux-form, and since then I've been trying to use it in the following way:
export const searchPermissions = () => {
return dispatch => {
Axios.get(`${URL}/findPermissions`)
.then(resp => {
console.log(resp.data);
dispatch({ type: PERMISSIONS_SEARCHED, payload: resp.data });
})
.catch(error => {
console.log(error);
throw new SubmissionError({
_error: "Submission error!"
});
});
};
};
And I keep getting the Uncaught error.
Searching through redux-form's github, I saw several similar problems that ended up being solved by adding the return statement (which I think I did correctly) and now I'm kinda lost.
Thanks in advance for any help.
EDIT:
I'm trying to fetch the permissions to display them in 3 combo boxes as soon as the user enters the page. In the component used to fetch the data I have the following code:
componentWillMount() {
this.props.searchPermissions();
}
render() {
return (
<div>
<LayoutGroupForm
onSubmit={this.props.addLayoutGroup}
loadPermissions={this.props.loadPermissions}
visualizationPermissions={this.props.visualizationPermissions}
detailPermissions={this.props.detailPermissions}
resetForm={this.props.resetForm}
/>
</div>
);
}
}
const mapStateToProps = state => ({
loadPermissions: state.layoutGroup.loadPermissions,
visualizationPermissions: state.layoutGroup.visualizationPermissions,
detailPermissions: state.layoutGroup.detailPermissions
});
const mapDispatchToProps = dispatch =>
bindActionCreators(
{
searchPermissions,
addLayoutGroup,
resetForm
},
dispatch
);
And on my reducer I have the following:
case PERMISSIONS_SEARCHED:
return {
...state,
loadPermissions: action.payload.loadPermissions,
visualizationPermissions: action.payload.visualizationPermissions,
detailPermissions: action.payload.detailPermissions
};

For those of you who still encounter this issue (like me), the solution is to add return to your submit handler.
Read more here
https://github.com/erikras/redux-form/issues/2269

Redux Form is expecting the error to come as the error in a rejected promise. Try this:
export const searchPermissions = () => {
return dispatch => {
return Axios.get(`${URL}/findPermissions`)
// ^^^^^^-------------------------------------- Actually return the promise!
.then(resp => {
console.log(resp.data);
dispatch({ type: PERMISSIONS_SEARCHED, payload: resp.data });
})
.catch(error => {
console.log(error);
return Promise.reject(new SubmissionError({
// ^^^^^^^^^^^^^^^^^^^^^^------------------------ Return rejected promise
_error: "Submission error!"
}));
});
};
};

Related

Add Async/Await to React Fetch Request

I'm making a fetch request to this API and I'm successfully getting the data and printing it to the console. However I'm new to asynchronous calls in Javascript/React. How do add async/await in this code to delay the render upon successful fetch? I'm getting the classic Uncaught (in promise) TypeError: Cannot read property '0' of undefined because I believe that the DOM is trying to render the data that hasn't been fully fetched yet.
import React, { useEffect, useState } from "react";
export default function News() {
const [error, setError] = useState(null);
const [isLoaded, setIsLoaded] = useState(false);
const [stories, setStory] = useState([]);
useEffect(() => {
fetch(
"http://api.mediastack.com/v1/news"
)
.then((res) => res.json())
.then(
(result) => {
setIsLoaded(true);
setStory(result);
console.log(result.data[0]); // printing to console to test response
console.log(result.data[0].title); // printing to console to test response
},
(error) => {
setIsLoaded(true);
setError(error);
}
);
}, []);
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div>
<p>{stories.data[0].title} </p> // this is the where render error is
</div>
);
}
}
The problem is that your isLoaded state variable is updated BEFORE stories, despite the fact you set the former state first. Here is how to fix this:
import { useEffect, useState } from "react";
export default function App() {
const [error, setError] = useState(null);
const [stories, setStory] = useState(null);
useEffect(() => {
fetch("your_url")
.then((res) => return res.json())
.then((result) => {
setStory(result);
console.log("Success ", result);
})
.catch((error) => {
console.log("Error", error);
});
}, []);
if (error) {
return <div>Error: {error.message}</div>;
} else if (!stories) {
return <div>Loading...</div>;
} else {
return (
<div>
<p>stories.data[0].title} </p>
</div>
);
}
}
Get rid of the isLoaded var altogether and use the stories var to indicate that it's being loaded.
If you want to add artificial load time to your api call. You can do something like this:
useEffect(() => {
fetch("your_url")
.then((res) => return res.json())
.then((result) => {
setTimeout(() => setStory(result), 2000)
})
.catch((error) => {
console.log("Error", error);
});
}, []);
This will add 2 seconds before setting your state thus letting you see what your loader looks like.
async/await is just another form to retrieve asynchronous data, like you are doing with then.
The message:
Cannot read property '0' of undefined
means that 'result.data' is undefined.
Anyway, if it entered the "then" callback it always means that the request was fetched, there is no such thing as "half fetched" or "fully fetched".
I suggest you to use the debugger, by placing
debugger;
right in the beginning of the 'then' callback to ensure what your result is.
or you may also console.log the result.
Just to clarify:
myFunctionThatReturnsPromise.then(response => //do something with response)
is the same as
await response = myFunctionThatReturnsPromise;
You might consider using stories?.data?.[0]?.title to fix this problem.
your error will not be gone with async await because you are calling a nested empty object which has no value. render method in react is prior to the useEffect you have used. you can approach two solutins:
1.use optional chaining es20 feature like this:
<p>{stories?.data?.[0]?.title} </p>
2.use nested if statement before the p tag to check whether it has data or not:
it seems the first option is much cleaner
You already have async code using Promise.then so async/await will not help you here - it's just a different way of writing Promise-based functionality.
Your problem is just as you say - React is trying to render your else block before stories has anything for you to render. I think you just need to write stricter conditions, e.g.
if (error) {
return <div>Error: {error.message}</div>;
}
if (!isLoaded || !stories.data.length) {
return <div>Loading...</div>;
}
return (
<div>
<p>{stories.data[0].title} </p> // this is the where render error is
</div>
);

ReactJS - Javascript try/catch shows an error in the console

I'm pretty new on React and I'm learning this language nowadays.
For this purpose I'm building a test project on which I try to encounter the main classical issues and looking to solve it.
For most of React developpers, there are no difficulties in following code but I will give a few details for better comprenhension.
I have a portion of javascript code that is returning a list of articles from a Symfony Backend API only if user is authorized for getting it (Authorization via JWT will be done later). A getArticles function returns a Promise that tries to get the articles from the Symfony backend inside a try {} catch (error) {} block.
Voluntarily, Authorization token is not send to trigger an error in the query.
As the axios.get is located inside a try {} catch (error) {} block, I am surprised that an error appears in the console for the request. It doesn't impact the behavior but it is not very clean to have these errors in the console.
My question(s) :
Why an error appears in the console while the code is inside a try/catch ? To get a cleaner app behavior, is there a way to avoid having this error in the console ? I have found other React try/catch issues but I didn't deduct the similarity with my issue. Am I missing something ?
Thanks in advance ;-)
I am aware that my code could be refactored, do not hesitate to suggest any good practice
componentDidMount(){
/*To be prepared to attach JWT token*/
axios.interceptors.request.use(req => {
return req;
});
const getArticles = async() => { return new Promise( (resolve, reject)=> {
try{
const data = axios.get('https://xxxxx/api/articles');
resolve(data);
} catch (err) {
reject(err);
}
});
}
getArticles().then(res => {
const articles = res.data.data.items;
this.setState( {errorOnArticlesLoading:false, articles: articles } );
})
.catch(error => {
this.setState( {errorOnArticlesLoading:true} );
});
}
You can try in this way and Async functions itself returns a promise, you don't need to return a new Promise manually.
async componentDidMount() {
try {
/*To be prepared to attach JWT token*/
axios.interceptors.request.use(req => req);
const getArticles = async () => {
try {
const data = axios.get('https://xxxxx/api/articles');
this.setState({ errorOnArticlesLoading: false, articles: data.data.items });
} catch (err) {
this.setState( {errorOnArticlesLoading:true} );
}
};
await getArticles()
} catch(err) {
console.log('Handled root error')
}
}
It seems that there are no solutions to avoid the 401 http error code in the console because it it printed by Chrome itself: See discussion here. So the following code cannot avoid the 401 error status to be printed in the console.
componentDidMount(){
/*To be prepared to attach JWT token*/
axios.interceptors.request.use(req => {
return req;
});
const getArticles = async() => {
const data = await axios.get('https://xxxx/api/articles');
return data;
}
getArticles().then(res => {
const articles = res.data.data.items;
this.setState( {errorOnArticlesLoading:false, articles: articles } );
})
.catch(error => {
this.setState( {errorOnArticlesLoading:true} );
});
}

React Native: Possible Unhandled Promise Rejection (id: 0): TypeError: undefined is not an object

I have a React Native application that I cloned and after registering into the app on my simulator, I get this yellow error at the bottom of the screen which says:
Possible Unhandled Promise Rejection (id: 0): TypeError: undefined is
not an object (evaluating 'data.Items')
I believe it has to be referencing one or all of these action creators in this file:
export function fetchPrefences({Key}) {
return dispatch => {
const url = `${endpoints.v2.INDIVIDUALS}/${Key}/preferences`;
requester.sendGet(url).then(data => {
const payload = helpers.sortPreferences(data);
dispatch({
type: types.SET_USER_PREFERENCES,
payload,
});
});
};
}
export function fetchTopics() {
return dispatch => {
requester.sendGet(endpoints.TOPICS_OF_CONCERN).then(data => {
dispatch({
type: types.SET_USER_TOPICS,
payload: data.Items,
});
});
};
}
export function handleUpdateTopics({topics, involved}, updateBoth = false) {
return dispatch => {
return requester
.sendPut(endpoints.TOPICS_OF_CONCERN, {
Items: topics,
})
.then(data => {
dispatch({
type: types.SET_USER_TOPICS,
payload: data.Items,
});
if (updateBoth) {
dispatch(handleUpdatePreferences({involved}));
}
});
};
}
I have written asynchronous action creators in the past, but I can't see what is wrong with these. Is it that data is undefined? If so, my question would be, how is this possible if in other areas of the application data is being used with no obvious errors?
Your data result is undefined ... it has nothing todo with your redux action
One easy and straight forward way to check your api-endpoint is postman ...

AsyncStorage.setItem Promise not fulfilling or erroring?

I've looked through a few posts such as this post
I want to use a console.log to see if I successfully set an item to AsyncStorage.
Here is my code:
export function saveDeckTitleAPI(key,title) {
return AsyncStorage.setItem(uuid(), JSON.stringify(new DeckCreator(title)))
.then(data => {
debugger;
console.log('INSIDE SET ITEM');
AsyncStorage.getItem(data.key).then(item => {
console.log(item);
})
})
.catch(err => {
console.err(err);
});
}
When I run this code, the .then and the .catch aren't fulfilled. I tried logging the promise by itself, and I get a similar result as the post above.
Do I have to use async/await? Is that the problem here? Here are the docs to setItem.
You can pass a callback as the third argument. If there's an error, it will be the callback's first parameter. If there's no error, console log that all is well and good, otherwise log the error.
Yes you need async and await
You can get an inspiration from the code below, the way I do a facebook login with setItem
const doFacebookLogin = async dispatch => {
const { type, token } = await
Facebook.logInWithReadPermissionsAsync('xxxx', {
permissions: ['public_profile']
});
if (type === 'cancel') {
return dispatch({ type: FACEBOOK_LOGIN_FAIL });
}
await AsyncStorage.setItem('fb_token', token);
dispatch({ type: FACEBOOK_LOGIN_SUCCESS, payload: token });
};

React dangerouslySetInnerHTML error causing promise rejection in Redux

I have a React component set up to display content from a CMS, where I use dangerouslySetInnerHTML. I have a standard fetch, request, receive pattern set up with a thunk to handle the async action.
The action creator looks like this:
export const fetchPage = (slug) => {
return (dispatch) => {
dispatch(requestPage());
return fetch(`${config.api}/pages/?slug=${slug}`)
.then((response) => {
const status = response.status;
switch (status) {
case 200:
return response.json();
case 401:
return Promise.reject(status);
default:
return Promise.reject(status);
}
})
.then(json =>
dispatch(receivePage({
slug,
json,
}))
).catch(err =>
dispatch(receivePageError(err)));
};
};
When I first created the React component, I forgot to pass to dangerouslySetInnerHTML the object in format { __html: content } and just passed it content, giving me the invariant violation. What confuses me is that this error bubbled up into the redux async flow and caused a dispatch of receivePageError. Why did this error show up here, rather than in the React component itself?
The error has been caught by the Promise's catch. The code example will console log the exception.
const callAnError = () => {
throw Error('Error');
}
const callAnErrorParent = () => {
callAnError();
}
const callAnErrorGrandparent = () => {
callAnErrorParent();
};
Promise.resolve().then(() => {
callAnErrorGrandparent();
}).catch((error) => {
console.log(error);
});
https://jsfiddle.net/nfyeu5co/1/
This is great resource for understanding promises
https://github.com/getify/You-Dont-Know-JS/blob/master/async%20%26%20performance/ch3.md

Categories

Resources