ReactJS Formik, Why is the form not clearing? - reactjs

I have Form
const TextForm = props => (
<Formik
initialValues = {{
text: '',
target: props.target
}}
onSubmit = {(values, { setSubmitting, resetForm }) => {
if (values.target == 'add') {
Request('POST', {"text":values.text});
resetForm({"text":""});
setSubmitting(false);
}
}}
>
{({
handleChange,
handleSubmit,
values,
}) => (
<form onSubmit={handleSubmit}>
<input type="hidden" name="target"/>
<textarea className={styles.text} value={values.text} name="text" onChange={handleChange}></textarea><br/>
<button type="submit">
Submit
</button>
</form>
)}
</Formik>
);
And data send ok. But the form doesn't clear. Why??
I also try this:
TextForm.setFieldValue('text', '');
But this doesn`t work too.

Check that the following function call is not throwing an exception:
Request('POST', {"text":values.text});
If an exception is being thrown from Request(..), then the subsequent call to resetForm(..) and setSubmitting(..) will be skipped which would be the reason for the problem you're experiencing.
Also, some improvements you might consider would be to make the following changes to your onSubmit handler:
/* Define onSubmit callback as async */
onSubmit = { async (values, { setSubmitting, resetForm }) => {
try {
if(values.target == 'add') {
/*
If request is async or returns a promise, wait
for it before resetting form
*/
await Request('POST', {"text":values.text});
resetForm({"text":""});
}
}
/*
If you want to handle errors here, do so with a
catch block like so:
catch(err) {
handleErrorHereIfYouChose(err);
}
*/
finally {
/*
Always ensure form submit state is reset, even if
unhandled is exception thrown
*/
setSubmitting(false);
}
}}

Me helped values.text = '';
onSubmit = {async (values, { setSubmitting, resetForm }) => {
try {
if (values.target == 'add') {
await fetch('http://localhost:3000/notes', {
headers: {
'Content-Type': 'application/json',
},
method: 'POST',
body: JSON.stringify({"text":values.text}),
});
values.text = '';
}
}
finally {
setSubmitting(false);
}

Related

How can i clean up such a function when not using useEffect hook?

I am using the function below with formik. It runs as expected but i noticed that when a user navigates away from the screen it's running, there's a memory leak of Can't perform a React state update on an unmounted component. How can I clean this up to clear subscriptions? Am okey using hooks. How would it look like?
const forgotPassword = async (values, formikActions) => {
try {
setIsLoading(true);
const response = await client.post("/user/post-reset-email", {
email: values.email,
url: "https://productionServer/mobileClient-reset-password",
});
// console.log(response, "Res Needed");
formikActions.setSubmitting(false);
formikActions.resetForm();
if (!response.ok) {
updateNotification(setMessageError, response?.data?.message);
} else {
updateNotification(setMessageError, response?.data?.message, "success");
}
formikActions.resetForm();
setIsLoading(false);
} catch (error) {
console.log(error, "Error Captured");
}
};
UpdateNotification is an imported helper function but this is how it looks like;
export const updateNotification = (updater, text, type = "error") => {
updater({ text, type });
setTimeout(() => {
updater({ text: "", type: "" });
}, 3000);
};
Thank you!
then just call this is a Form....
<Form
initialValues={{ email: "" }}
onSubmit={forgetPassword}
validationSchema={validationSchema}
>
<FormField
name="email"
autoCapitalize="none"
autoCorrect={false}
icon="email"
keyboardType="email-address"
placeholder="Enter Email..."
/>

Axios post request of form data send nothing

I need to send form data to my database with an Axios post request, but nothing is sent.
The data I need is what is in movieId input.
Maybe the formData.append is not well written ?
const { register, handleSubmit } = useForm();
const onSubmit = data => {
const formData = new FormData();
formData.append('movieId', data.movieId);
axios.post("http://localhost:5000/addMovie", formData)
.then(response => {
console.log("Status: ", response.status);
console.log("Data: ", response.data);
}).catch(error => {
console.error('Something went wrong!', error);
});
}
return (
<div id="ModalBackground">
<div id="ModalContainer">
<button id= "closeModal" onClick= {() => {closeModal(false)}}>X</button>
<h1 id= "formTitle">Numéro du film</h1>
<form onSubmit={handleSubmit(onSubmit)} id="addMovieForm">
<input type="text" id="movieId" {...register("movieId")} required></input>
<input id= "submit" type="submit" value="Ajouter !"></input>
</form>
</div>
</div>
);
}
export default Modal```
Something is wrong there, i saw you have something specific for the handle submit, so you need to cast your call differently. Because when you do directly onSubmit={handleSubmit(onSubmit)} you are calling directly this method on every render/update
<form onSubmit={handleSubmit(onSubmit)} id="addMovieForm"
<form onSubmit={() => handleSubmit(onSubmit)} id="addMovieForm">
// if you wish to cast the event aswell
<form onSubmit={e => handleSubmit(e,onSubmit)} id="addMovieForm">
I use react hook form (https://react-hook-form.com/get-started), and the doc say that :
const { register, handleSubmit, watch, formState: { errors } } = useForm();
const onSubmit = data => console.log(data);
console.log(watch("example")); // watch input value by passing the name of it
return (
/* "handleSubmit" will validate your inputs before invoking "onSubmit" */
<form onSubmit={handleSubmit(onSubmit)}>```
So I don't know what I have to do xD
Change onSubmit={handleSubmit(onSubmit)} to onSubmit={handleSubmit} as the former is supported in HTML but not in React.
<form onSubmit={handleSubmit} id="addMovieForm">
Add a name attribute to the input field so that the key value pair for this particular input field can be stored inside FormData. This eliminates the formData.append step inside handleSubmit().
<input type="text" id="movieId" name="movieId" required></input>
You need to specify Content-Type: multipart/form-data inside the header of the POST request.
const handleSubmit = (e) => {
e.preventDefault();
// Passing form element (e.target) populates the FormData object with the names and values of the fields inside it.
const formData = new FormData(e.target);
// formData.append("movieId", data.movieId);
// To check formData because simply console.log(formData) won't work
for (let item of formData) {
console.log(item);
}
axios
.post("http://localhost:5000/addMovie", formData, {
headers: { "Content-Type": "multipart/form-data" },
})
.then((response) => {
console.log("Status: ", response.status);
console.log("Data: ", response.data);
})
.catch((error) => {
console.error("Something went wrong!", error);
});
};

React Bootstrap reset form after submit

Hello I am trying to setup a contact form with React Bootstrap in a React/Next.js app. How would I reset the form after submitting it? When I added a reset handle the validation did not work anymore.
// Form validation
const [validated, setValidated] = useState(false);
// Thank you Message
const [thankYouMessage, setThankYouMessage] = useState(false);
// Form submit handler
async function handleSubmit(e) {
e.preventDefault();
e.stopPropagation();
const formData = new FormData();
Array.from(e.currentTarget.elements).forEach((field) => {
if (!field.name) return;
formData.append(field.name, field.value);
});
await fetch(
"https://domain.tld/wp-json/contact-form-7/v1/contact-forms/1234/feedback",
{
body: formData,
method: "POST",
}
)
.then((response) => response.json())
.then((response) => {
if (response.status === "mail_sent") {
setThankYouMessage(!thankYouMessage);
} else if (response.status === "mail_failed") {
alert("Message failed to send.");
}
});
setValidated(true);
}
This is the form:
<div>
<Form
noValidate
validated={validated}
onSubmit={handleSubmit}
>
<Form.Group controlId="your-name">
<Form.Control
required
type="text"
placeholder="Your name"
name="your-name"
/>
<Form.Control.Feedback type="invalid">
Please enter your name
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="your-email">
<Form.Control
required
type="email"
placeholder="Your email address"
name="your-email"
/>
<Form.Control.Feedback type="invalid">
Please enter your email
</Form.Control.Feedback>
</Form.Group>
<Form.Group controlId="your-message">
<Form.Control
as="textarea"
cols={30}
rows={6}
placeholder="Write your message..."
name="your-message"
/>
</Form.Group>
<Button type="submit" variant="primary" size="lg">
Send Message
<span></span>
</Button>
</Form>
<Alert
variant="success"
className={thankYouMessage ? "d-block mt-3" : "d-none"}
>
Thank you for your message. It has been sent.
</Alert>
</div>
I have tried setting up a reset handle with useRef() but it did not work:
const formRef = useRef(null);
const handleReset = () => {
formRef.current.reset();
setValidated(false);
};
Then on the form added ref={formRef} and right after setValidated(true); I did handleReset(); but then the validation does not work anymore.
Any suggestions about this are welcome and any comments on the code as well!
Here's an gif of what happens when adding ref={formRef} to the Form tag and:
const formRef = useRef();
const handleReset = () => {
formRef.current.reset();
setValidated(false);
};
and in the fetch:
.then((response) => response.json())
.then((response) => {
if (response.status === "mail_sent") {
setThankYouMessage(!thankYouMessage);
handleReset();
} else if (response.status === "mail_failed") {
alert("Message failed to send.");
}
});
From what I understand, you want to get response first before resetting? e.preventDefault() is preventing the form from resetting, but by removing that, the page just reloads immediately without waiting for the response. If that is the issue that you're facing, then there are a few solutions:
Use reload (just reloads the current document).
.then((response) => {
if (response.status === "mail_sent") {
setThankYouMessage(!thankYouMessage);
} else if (response.status === "mail_failed") {
alert("Message failed to send.");
}
location.reload();
});
Use submit (just submits form without sending submit event or form validation but this is fine because you have already validated it previously).
const formRef = useRef(null);
...
.then((response) => {
if (response.status === "mail_sent") {
setThankYouMessage(!thankYouMessage);
} else if (response.status === "mail_failed") {
alert("Message failed to send.");
}
formRef.current.submit();
});
...
<Form
noValidate
validated={validated}
onSubmit={handleSubmit}
ref={formRef}
>
Use requestSubmit (same as clicking the submit button). EventListener is needed here because essentially, what you want is to disable default action by calling preventDefault first, then enable default action again after getting response. Unfortunately, there is no such convenient enableDefault function.
The flow is like this:
addEventListener with preventDefault is called (now any button clicks will not reset the form)
Fill the form and click submit button
Fetch and received response
removeEventListener with preventDefault is called (now any button clicks will reset the form)
call requestSubmit to submit the form as if the submit button is clicked, which will reset the form
const formRef = useRef(null);
...
// useCallback is needed here instead of a normal function because
// formRef will be updated every time onChange occurs because react renders again
// which will cause addEventListener/removeEventListener to not work as expected
const stopReset = useCallback((event) => {
event.preventDefault();
// stopPropagation will prevent form validation but if you really need it here
// then you need to add another event listener for handleSubmit in useEffect
// and you can remove onSubmit={handleSubmit} in Form
// event.stopPropagation();
}, []);
useEffect(() => {
formRef.current.addEventListener('submit', stopReset);
// Uncomment this only if you need stopPropagation above
// formRef.current.addEventListener('submit', handleSubmit);
},[]); // Add dependencies in the array, leave it blank if you don't have any
async function handleSubmit(e) {
// remove preventDefault and stopPropagation here
const formData = new FormData();
Array.from(e.currentTarget.elements).forEach((field) => {
if (!field.name) return;
formData.append(field.name, field.value);
});
await fetch(
"https://domain.tld/wp-json/contact-form-7/v1/contact-forms/1234/feedback",
{
body: formData,
method: "POST",
}
)
.then((response) => response.json())
.then((response) => {
if (response.status === "mail_sent") {
setThankYouMessage(!thankYouMessage);
} else if (response.status === "mail_failed") {
alert("Message failed to send.");
}
formRef.current.removeEventListener('submit', stopReset);
formRef.current.requestSubmit()
});
setValidated(true);
}
...
<Form
noValidate
validated={validated}
onSubmit={handleSubmit}
ref={formRef}
>
If you want to display your message for awhile before resetting, you can add a timer.
.then(async (response) => {
if (response.status === "mail_sent") {
setThankYouMessage(!thankYouMessage);
} else if (response.status === "mail_failed") {
alert("Message failed to send.");
}
// sleep for 10 seconds
await new Promise(r => setTimeout(r, 10000));
// call whichever method to reset
});

How to use sign in with email and password with Firebase?

This is going to be my longest post on Stack Overflow and I'm not proud of it. The focus should be on the first two code blocks in which I define the functions handling firebase. The other bits are just a sanity check that I am not missing anything simple.
The problem is that my form won't be submitted (and the functions inside of the onSubmit don't even run). After clicking the 'submit' button, I'd like to register a user to Firebase with email and password. That doesn't work as it stands.
async createUserProfileDocument(user, additionalData) {
if (!user) return
const userRef = this.firestore.doc(`users/${user.uid}`)
const snapshot = await userRef.get()
if (!snapshot.exists) {
const { displayName, email, photoURL } = user
const createdAt = moment().format('MMMM Do YYYY, h:mm:ss a')
try {
await userRef.set({
displayName,
email,
photoURL,
createdAt,
...additionalData,
})
} catch (error) {
console.error('error creating user: ', error)
}
}
return this.getUserDocument(user.uid)
}
export const Register = () => {
const history = useHistory()
async function writeToFirebase(email, senha, values) {
try {
const { user } = await firebaseService.auth.createUserWithEmailAndPassword(email, senha)
firebaseService.createUserProfileDocument(user, values)
history.push('/')
} catch (error) {
console.error('error: ', error)
}
}
function onSubmit(values, { setSubmitting }) {
values.displayName = values.user.nome
writeToFirebase(values.user.email, values.user.senha, values)
setSubmitting(false)
}
return (
<div className="booking">
<Formik
initialValues={initialValues}
validationSchema={Yup.object({ ...validationService.generateBasicUserSchema() })}
onSubmit={onSubmit}>
<Form>
<EWUserBasicDataFields />
<button type="submit">Submit</button>
</Form>
</Formik>
</div>
)
}
As I said in the comments
Do some testing, remove validationSchema and see if you can submit the form. If you can, the problem is that the form is invalid. Also check in the console to see if you don't have any errors.

Redux form submitSucceeded property is set to true before the submission fails

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?

Resources