React useState Hook - Can't Clear State on Form Data - javascript

Slightly novice react hooks user here. Trying to submit a blog post form, consisting of a title, author and URL. I can submit my form correctly and values are saving in database, but I can't clear the data from the form.
I'm holding state like this
const [newBlog, setNewBlog] = useState({ url: "", author: "", title: "" });
and handling form change to update state like this:
const handleBlogChange = e => {
const { name, value } = e.target;
setNewBlog({ ...newBlog, [name]: value });
};
example setup of one my input fields (identical across all three)
<form className="form" onSubmit={addBlog}>
<div className="col-lg-9">
<input
className="form-control"
id="title"
aria-describedby="emailHelp"
placeholder="Enter title"
name="title"
value={newBlog.title}
onChange={handleBlogChange}
/>
</div>
and this is my addBlog function. you can see where I commented out one version of clearing the state which is causing problems.
const addBlog = event => {
event.preventDefault();
const { url, title, author } = newBlog;
const blogObject = {
url,
title,
author
};
blogService
.create(blogObject)
.then(data => {
setBlogs(blogs.concat(data));
showMessage(`Success! ${newBlog.title} by ${newBlog.author} was added`);
// setNewBlog([...newBlog, { url: "", title: "", author: "" }]);
})
.catch(error => {
showMessage(
`Sorry can't add blog. Here's why: ${error.response.data.error}`,
false
);
});
};
I've also tried different variations which are leaving the data in the form, no errors, but not clearing out the form. Examples of this include
setNewBlog(''), setNewBlog([]) and
setNewBlog(newBlog.title='')
Nothing is working.

Related

How to put data in fields when updating?

Here is the scenario:
I want to use the same form to create a product and update a product.
The form is made with components of Material UI (TextFields).
My product creation form works (unless no image is put).
To update, I manage to return the information to my form, but I don't know how to put its data in my fields (Probably with value but I have errors (null or undefined).
Here is the head of my form (Creation and modification) :
(Same form, only the title change (Modification of a Product)
Here is the link to send the product information to be modified to my form page :
<Link to={`/produit/${produit.id}`}>
The axios request made by getProduitById(id) :
export const getProduitById = (id) => axios.get(`${APIURL}/produit/:id`.replace(':id', id));
And finally, the code of how I get the product information :
useEffect(() => {
getMarque()
if (id) {
getProduitById(id).then(response => {
if (response.data){
console.log(response.data.marqueId)
setProduit({
nom: response.data.nom,
prix: response.data.prix,
description: response.data.description,
qtestock: response.data.qtestock,
})
}
}).catch(err => console.log(err));
}
}, [])
And that's it. I try to ensure that, when I arrive on the form following my modification Link, the fields are filled with the previous information of the product
(And a little screen to show you that I get the product information in my console :)
I was able to resolve my problem with 'value' and a function 'onChange'
For anyone, here's the code :
Form :
<TextField style={TextFieldStyle} value={produit.nom} id='nom' name='nom' onChange={handleChange} placeholder='Entrez le nom du produit' type='string' fullWidth required variant='outlined' />
How I got my product information :
useEffect(() => {
if (id) {
getProduitById(id).then(response => {
if (response.data){
console.log(response.data)
setProduit({
nom: response.data.nom,
prix: response.data.prix,
description: response.data.description,
imageurl: response.data.imageurl,
qtestock: response.data.qtestock,
marqueId: response.data.marqueId,
})
console.log(produit)
}
}).catch(err => console.log(err));
}
}, [])
onChange :
const [produit, setProduit] = useState([]);
const handleChange = (e) => {
const value = e.target.value;
setProduit({
...produit,
[e.target.name]: value });
}

How can I disable validation on submit?

I have a multistep form, and I keep each step under a single <Formik /> tag. The initial values and validation schemas are kept in objects for each step:
const initialValues = {
step1Values: { ...values1 },
step2Values: { ...values2 },
step3Values: { ...values3 },
}
const validationSchema = Yup.object().shape({
step1Schemas: { ...yupSchema1 },
step2Schemas: { ...yupSchema2 },
step3Schemas: { ...yupSchema3 },
});
// in component render/return:
<Formik
initialValues={initialValues}
validationSchema={validationSchema}
validateOnMount
validateOnBlur
/>
Each step has its own component rendered within the Formik tag, and use useFormikContext to grab values, errors, i.e. with const formikProps = useFormikContext(), then for a given value of a field, I can say:
// in step 1
<input
name="step1Values.someValue"
value={step1Values.someValue}
onChange={formikProps.handleChange}
/>
I want all components under the same form umbrella for persistence purposes (form values will persist even as they change from one step to another). However, there are certain cases where the user can skip step one or two and not fill them out, and jump to step 3 (based on state of the redux-store). Submitting the form is only dependent on step 3 being properly validated according to formik.
I have internal checks in components 1 and 2 to move through those steps, but I want formik to track the errors to show errors if the fields are empty after having been touched. In cases where users can skip step 1 or 2, the validation schema has errors because those fields are considered required. I have a custom validation function customValidate which returns true or false, and which is based on the current state of formikProps.errors.step3. The submit button is disabled until customValidate returns true, so I really don't need formik to validate on submit - in fact, I need it to not validate on submit, so that the onSubmit function fires properly from step 3, regardless of errors in step 1 or 2.
How can I keep validateOnMount and validateOnBlur, but prevent validate on submit? I wish there was a validateOnSubmit={false} option, but I don't see that. There must be a way?
I have a workaround for you: Just remove the validation Schema, validateOnMount, validateOnBlur because we are going to handle them ourselves.
make your Formik as Follows
<Formik
initialValues={initialValues}
/>
you will need this function to format the errors for you:
const getErrorMessages = ({ path, message, inner }) => {
if (inner && inner.length) {
return inner.reduce((acc, { path, message }) => {
acc[path] = message;
return acc;
}, {});
}
return { [path]: message };
};
and then you can validate your form onMount using useEffect like follows
useEffect(() => {
try {
validationSchema.validateSync(values, { abortEarly: false });
setErrors({});
} catch (error) {
setErrors({ ...getErrorMessages(error) });
}
}, []);
and for the onBlur make your own Function
const handleBlur = async (e) => {
setFieldTouched(e.target.name, true);
try {
validationSchema.validateSync(values, { abortEarly: false });
setErrors({})
} catch (error) {
setErrors({ ...getErrorMessages(error) });
}
};
finaly to your inputs you can make them as follows:
<input
name="step1Values.someValue"
value={step1Values.someValue}
onChange={formikProps.handleChange}
onBlur={handleBlur}
/>
final Notes:
you have to use your custom onBlur on all fields or it won't validate onBlur
you can make the same thing with onChange if you want just make a custom function like handleBlur one.

Showing modal on successfully posting data from redux

Hey guys i am using React Hooks with redux, so what i want is lets say user need a signup on my website, so after posting his details i am sending back status :200 and if it has status:200 i am updating a state value in my userReducer like say "status" to true (which initially was false) and based on this boolean value i am showing a modal to user with the message. So code goes like
Actions.js
export const userRegisterAction = (data: any) => async (dispatch: any) => {
console.log(data);
axios.post("http://localhost:4000/register_user", data).then((res) => {
console.log("hittinh server");
console.log(res.data);
if (res.data.status == 200) {
dispatch({
type: USER_REGISTRATION_SUCCESS,
payload: res.data,
});
} else {
dispatch(errorActions());
}
});
};
Reducer.js
case USER_REGISTRATION_SUCCESS:
return {
...state,
status: true,
info: action.payload.doc.ops[0],
};
and then in my component
const user = useSelector((state: RootState) => {
console.log(state.user.info);
console.log(state.error.iserror);
return { user: state.user };
});
<IonAlert
isOpen={user.user.status == true}
cssClass="my-custom-class"
header={"User Registered!"}
backdropDismiss={false}
// subHeader={'User Registered !'}
message={"You have been registered successfully."}
// buttons={["OK"]}
buttons={[
{
text: "OK",
handler: () => {
console.log("Confirm Okay");
redirect();
},
},
]}
/>
Note. I am using redux persist and this reducer needs to be persisted for future purpose as i am gonna use this wherever i need user related task like if he needs to change password i will pick up the email from my user reducer so it doesnt gets lost on refresh
NOW COMING TO THE ISSUE, as my reducer state is persisted once the "status" is true if user wishes to signup from another account as soon as he goes to signup page he will again see the result of "ionAlert" as it will match the condition status==true , so what i am doing is on every unmount i am dispatching action which sets "status" to false, although this works fine, but i wanna know is this the correct approach , how are you all dealing with this stuff ??

Service ID invalid when trying to use EmailJS with React

I created a form to contact me on my website, for that I use EmailJS.
However when I try to send myself a mail through the contact form I got a 400 Error The service ID is invalid.
I followed every steps of that tutorial as I haven't use EmailJS before https://blog.mailtrap.io/react-send-email/
Here is my Contact component
class Contact extends React.Component {
constructor(props) {
super(props);
this.state = { feedback: '', name: 'Name', email: 'email#example.com' };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
render() {
return (
<form className="test-mailing">
<h1>Let's see if it works</h1>
<div>
<textarea
id="test-mailing"
name="test-mailing"
onChange={this.handleChange}
placeholder="Post some lorem ipsum here"
required
value={this.state.feedback}
style={{width: '100%', height: '150px'}}
/>
</div>
<input type="button" value="Submit" className="btn btn--submit" onClick={this.handleSubmit} />
</form>
)
}
handleChange(event) {
this.setState({feedback: event.target.value})
}
handleSubmit() {
const templateId = 'template_id';
this.sendFeedback(templateId, {message_html: this.state.feedback, from_name: this.state.name, reply_to: this.state.email})
}
sendFeedback (templateId, variables) {
window.emailjs.send(
'gmail', templateId,
variables
).then(res => {
console.log('Email successfully sent!')
})
// Handle errors here however you like, or use a React error boundary
.catch(err => console.error('Oh well, you failed. Here some thoughts on the error that occured:', err))
}
}
And here is what I added in my index.html
`<script type="text/javascript"
src="https://cdn.jsdelivr.net/npm/emailjs-com#2.3.2/dist/email.min.js"></script>
<script type="text/javascript">
(function(){
emailjs.init("my_user_ID_here"); // Obtain your user ID at the dashboard https://dashboard.emailjs.com/integration
})();
`
To fix this, I had to swap out 'gmail' with my service ID.
sendFeedback (templateId, variables) {
window.emailjs.send(
***serviceID here***, templateId,
variables
).then(res => {
console.log('Email successfully sent!')
})
// Handle errors here however you like, or use a React error boundary
.catch(err => console.error('Oh well, you failed. Here some thoughts on the error that occured:', err))
}
The JavaScript console in my web browser helped identify this.
That was happening to me, and it was because I didn't have the account activated.
when you log in, click on 'email services' and select, for example, gmail with your account
pd: google translate
Had the same problem.
To fix it,
I had to paste NOT the 'gmail' string itself but the service_id which
is below the icon gmail
in the EmailJS website after log in. Everyone has its own specific number. Also the template_id is important to put the id generated for your template.
When you want to publish your project it is advisable to place your special ids to the .env file to stay secure.
Please try to check whether you are using the right integration id, check the id token you are using with the one under integration id on the dashboard, this was my issue
Might as well share a quick fix that would probably save someone's time. I just had the same issue while using the code below.
const notifyOwnerOfGuest = async () => {
const userId = 'user_...';
const serviceId = 'service_...';
const templateId = 'template_...';
const accessToken = 'e2e1...';
const postfields = {
user_id: userId,
service_id: serviceId,
template_id: templateId,
accessToken,
};
const response = await fetch('https://api.emailjs.com/api/v1.0/email/send', {
method: 'POST',
body: JSON.stringify(postfields),
// should explicitly add the header content-type here
});
if (!response.ok) throw await response.text();
};
I just explicitly added a Content-type header like so
headers: {
'Content-Type': 'application/json',
},
and now it works.

Select option child component not reseting to key 0 on form submit with reactjs

I have a select option child component (called Service) for a form because I am loading the values with a JSON file. Also, I am using event.preventDefault() within my handleSubmit() event so that the react-notifications success message displays correctly, rather than disappearing right away because of the re-render.
This is causing my select option fields to maintain the value that was selected before the form was submitted. I need these to be reset to key 0, so that I have a "fresh" form.
I realize that event.preventDefault() prevents the form from naturally resetting, so I am clearing the state of my form elements after. This does not reset the select options though.
I tried removing event.preventDefault() and this allows the form to reset, but then my react-notification success message does not show.
I have tried placing the react-notification message in a different life cycle method (componentDidUpdate()), but I have not been successful as the success message does not show.
Handle Submit
handleSubmit(event) {
event.preventDefault();
let formData = {
name: this.state.name,
phone: this.state.phone,
email: this.state.email,
service1: this.state.service1,
service2: this.state.service2,
service3: this.state.service3
};
fetch('/emails/requestform', {
method: 'post',
body: JSON.stringify(formData),
headers: {
"Content-Type": "application/json"
}
}).then(
this.createNotification('success'),
this.setState({name: ''}),
this.setState({phone: ''}),
this.setState({email: ''}),
this.setState({service1: ''}),
this.setState({service2: ''}),
this.setState({service3: ''})
).catch(error => console.log(`Error posting form: ` + error));
}
Service Component
import React from 'react';
import './Service.css';
class Service extends React.Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
this.handleSubmitForSelect = this.handleSubmitForSelect.bind(this);
}
handleChange(event) {
this.props.onServicesChange(event.target.value);
}
handleSubmitForSelect(event) {
this.setState(event.target.value = '');
}
render() {
let services = this.props.state.services;
let optionItems = services.map((service) => <option key={service.id} value={service.value}>{service.service}</option>);
return (<div >
<select className="select" value={this.props.value} onChange={this.handleChange} onSubmit={this.handleSubmitForSelect}>
{optionItems}
</select>
</div>)
}
}
export default Service;
I expect the form to fully reset and the react-notification success message to still show. But at the moment it seems like only one or the other is possible.
You need to pass a function argument to then() . Then your business logic goes inside the function
fetch('/emails/requestform', {
method: 'post',
body: JSON.stringify(formData),
headers: {
"Content-Type": "application/json"
}
})
.then((resp) => resp.ok ? resp.json() : Promise.reject('Bad request status = '+ resp.status))
.then((data) => {
// ^^^^^^^^^^ anonymous function argument
// do something with response data here
this.createNotification('success');// <== semi colon not comma
this.setState({
name: '',
phone: '',
email: '',
service1: '',
service2: '',
service3: ''
});
}).catch((err)=> console.error(err))

Categories

Resources