I don't know how can I easy resolve the problem. I have a form that user can fill and send stuff to my database. Form has his own state for it (here for example is just username). I don't know how to call setState (to give message to user about result) after dispatching redux action.
Function postDataBegin is simple and shows spinner only. I think there is a problem, cause this function is synchronous (tell me if not). How can i fix it? What should i learn?
submitForm = e => {
e.preventDefault();
const { username } = this.state;
if (!question) {
this.setState({ messageToUser: "Fill the form" });
} else {
// onSubmit is redux action from props
this.props.onSubmit(username);
//HOW TO CALL THIS FUNCTION AFTER FUNC ABOVE?
this.setState({ messageToUser: "Send" });
}
};
<Form type="submit" onSubmit={this.submitForm}/>
export const postUserQuestion = username => dispatch => {
dispatch(postDataBegin());
return post(postUsernameAPI, username)
.then(res => dispatch(postUsernameAPISucceeded(res)))
.catch(error => dispatch(postUsernameAPIFailure(error)));
};
Your action returns a promise, so you can use then method on it to provide a callback:
submitForm = e => {
e.preventDefault();
const { username } = this.state;
if (!question) {
this.setState({ messageToUser: "Fill the form" });
} else {
// onSubmit is redux action from props
this.props.onSubmit(username).then(() => {
this.setState({ messageToUser: "Send" });
});
}
};
Altho it'd probably be better to store that data on reducer as well, and change it the same time when the form is submitted.
Related
I'm creating a page login with OTP, so first I sent request for login. If it's successful then my model would open for entering the otp.
But in my case model will open always because im unable to figure out how check if my request is successfult or not
I can manage state but I don't want to manage state for this simple task. I just want that the request in action reducer is successful or not. This will surely solves my problem easily.
const handleSubmit = async (event) => {
event.preventDefault();
const data = new FormData(event.currentTarget);
let email= data.get('email');
let password= data.get('password');
await props.otpRequest(email,password);
handleOTPModelOpen();
};
Action Reducer
export const otpRequest = (email,password) => {
return (dispatch) => {
const url = process.env.REACT_APP_DEV_BACKEND
dispatch(getOTPRequest())
axios
.post(`${url}/api/get_otp`,{
email: email,
password: password
})
.then(response => {
dispatch(getOTPSuccess())
dispatch(showAlert(handleAxiosError(response),"success"));
})
.catch(error => {
dispatch(showAlert(handleAxiosError(error),"error"));
dispatch(getOTPFailure())
throw OTPRequestFailed()
})
}
}
and using mapDispatchToProps
const mapDispatchToProps = dispatch => {
return {
fetchToken: (email,otp) => dispatch(fetchToken(email,otp)),
otpRequest: (email,password) => dispatch(otpRequest(email,password))
}
}
I just want to check if otpRequest is successful or not. Like that we checkedd in axios request in action reducer.
All request are successful no error is coming
One nice way of handling this for most libraries is a try / catch block.
You could do this:
try {
await props.otpRequest(email,password);
handleOTPModelOpen();
} catch (e) {
// handle error here
console.log(e);
handleOTPFailed();
}
EDIT 1
I don't see a selector or use of mapStateToProps callback. You use mapDispatchToProps which is great for the actions, however, in order to access the resulting state, you must also add mapStateToProps. Here's an example from one of my apps:
const mapStateToProps = (state) => {
return {
success: state.data.success;
}
}
Think of state as a whole pie. A Redux selector allows you to take a slice of that pie and return it to the React component props for use, instead of the entire state (response from the API dispatch).
In my form, I'm trying to check email by using reactive-thunk to determine if the email address was already received. Everything is working properly, except for one thing. I request the api and I'm sending the data to the reducer, but the component I have access to the state is empty. Because the state value in the component is working before the reducer.
Is there any help of how to do that?
Submit.js
onSubmit = data => {
const { saveUser, validateEmail, emailValidate } = this.props;
validateEmail(data.email); // action create for api request
console.log(emailValidate); // fetch data in reducer(This data is empty because code run before reducer set state)
if (emailValidate.statusMessage === 'OK') {
throw new SubmissionError({ email: 'Email already in use', _error: 'Login failed!' });
} else {
}
}
const mapDispatchToProps = (dispatch) => {
validateEmail(email) {
dispatch(validateEmail(email));
},
};
};
const mapStateToProps = (state) => ({
emailValidate: state.registrationFormEmailValidate.data,
});
onSubmit = data => {
const { saveUser, validateEmail, emailValidate } = this.props;
validateEmail(data.email); // action create for api request
}
componentDidUpdate(prevProps) {
// Typical usage (don't forget to compare props):
if (this.props.emailValidate.statusMessage !== prevProps.emailValidate.statusMessage) {
console.log(this.props.emailValidate);
if (this.props.emailValidate.statusMessage === 'OK') {
throw new SubmissionError({ email: 'Email already in use', _error: 'Login failed!' });
} else {
}
}
}
If you are using class component, you can use componentDidUpdate()
I have this form code below:
submitForm = (e) => {
e.preventDefault();
const { user } = this.state;
const { dispatch } = this.props;
if (user.firstName && user.lastName && user.userName && user.password) {
this.props.dispatch(userActions.register(user));
} else {
this.setState({
error: "Form Incomplete"
})
}
if(this.state.error === "") {
this.props.history.push("/login");
}
}
The problem is this.props.dispatch is an async call. It gets fired when a user successfully fills out the form field.
The problem is it can fail if the username already exists and it will populate the error state. If this occurs my app keeps going and hits this.props.history and redirects the user even if the form has an error.
How do I basically say "Wait until this.props.dispatch is complete and then check to see if there are any errors. If not then redirect"?
You can specify submitForm as an async function like this:
submitForm = async (e) => {
and then add the await keyword before this.props.dispatch
await this.props.dispatch(userActions.register(user));
But since you are using redux, and I am assuming something like redux-promise-middleware, then you should let that handle the success/failure of your async calls.
You mentioned that onInit the form continuously redirects because there is no error set. Can we change the initial error value to false and if error is ever true then re-direct the user? And then, the only time you would ever set error to true would be when an actual error came from your call.
I imagine that you are sending this data to a backend of some sort. Just add a bool to the server response to let your front end know what to do next.
submitForm = (e) => {
e.preventDefault();
const { user } = this.state;
const { dispatch } = this.props;
if (!( user.password && user.lastName &&user.userName && user.firstName )) {
this.props.dispatch(userActions.register(user));
} else {
this.setState({
error: "Form Incomplete"
})
}
if(isValid) {
this.props.history.push("/login");
}
}
I have a form which calls a redux action and then clears the input fields if the post was successful . The issue seems to be after the input fields are cleared on a successful post the input fields turn red.
redux action function
postActionFunction = (data, clearDataFunction) => (dispatch) => {
axios
.post(`/endpoint`, data)
.then(() => {
console.log('success');
})
.then(() => {
clearDataFunction();
})
.catch((err) => {
console.log('error');
});
};
form submit function
onSubmit(e) {
e.preventDefault();
const { inputData } = this.state;
// below function is the redux action
this.props.postCategories(inputData, this.clearDataFunction);
}
clearDataFunction() {
this.setState({ inputData: '' });
}
Edit :
This seems to happen only with Firefox developer's edition
I am dispatching an action which makes an api call in redux-form asyncValidate method. The api call fails. I am trying to show the messages about successful and unsuccessful submit in the form, but submitSucceeded is always getting set to true before the api call fails. Therefore, I always get the message about successful submit before seeing the error message.
Before using asyncValidate, I tried the same thing inside onSubmit method. I throw an error inside the action, but that doesn`t help.
Here is the code for component:
const SubmissionForm = ({handleSubmit, submitFailed, submitSucceeded, asyncValidating}) =>
<Form onSubmit={handleSubmit}>
{submitFailed && <div>Failed</div>}
{submitSucceeded && <div>Succeeded</div>}
{asyncValidating && <div>Validating...</div>}
<Field name={`name`} type="text" component={"input"} />
</Form>
const enhancer = {
connect(null,{ editUser }),
reduxForm({
form: "editUser",
asyncBlurFields: [],
onSubmit: () => {},
asyncValidate: async (data, _, {editUser}) => {
return await editUser(data)
}
})
}
And the code for action:
const editUserStart = (user) => ({ type: EDIT_USER_START, user })
const editUserSuccess = (user) => ({ type: EDIT_USER_SUCCESS, user })
const editUserError = (error) => ({ type: EDIT_USER_ERROR, error })
const editUser = (data) => async dispatch => {
dispatch(editUserStart(data))
try {
const response = await api.postUserInfo(data)
if (response.error) {
throw new Error(response.error)
}else{
return dispatch(editUserSuccess(data))
}
} catch (e) {
dispatch(setSubmitFailed("editUser", e))
dispatch(editUserError(e))
}
}
How can I prevent the form from setting submitSucceeded before failing?
Probably your problem is with editUser function. Can you please console.log this const response = await api.postUserInfo(data) and make sure that response.error exists?