I have this form, and I would like to send these values. I know we have to use setState() to store data but how does it work for input type="hidden"?
First question: How to store input hidden to setState ?
Second question: How to serialize data like form.serialize() ?
Third question: How to send these serialize values? Ajax or Axios, who is the better?
Here is the code:
handleSubmit(e) {
e.preventDefault();
/**
$.ajax({
url: "post.php",
type: "POST",
data: DATA,
success:function(data) {
}
});
**/
}
<form onSubmit={this.handleSubmit}>
<input type="hidden" name="action" value="login" />
<input type="email" name="email_user" placeholder="Email" />
<input type="password" name="password_user" placeholder="Mot de passe" />
<button type="submit">Login</button>
</form>
The answer is complex for all your questions.
First of all, it depends on the task: if you just want to send asynchonous request to server on form submit, you don't need to use Component state. Here is a link to the relevant section of the documentation. And use refs to access inputs data.
class FormComponent extends React.Component {
constructor(props) {
super(props);
this.onSubmit = this.onSubmit.bind(this);
}
onSubmit(e) {
e.preventDefault();
// Send your ajax query via jQuery or Axios (I prefer Axios)
axios.get('your_url', {
params: {
action: this.actionInput.value,
email: this.emailInput.value,
password: this.passwordInput.value,
}
})
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
}
render() {
return (
<form onSubmit={this.onSubmit}>
<input type="hidden" name="action" value="login"
ref={(input) => { this.actionInput = input }} />
<input type="email" name="email_user" placeholder="Email"
ref={(input) => { this.emailInput = input }}/>
<input type="password" name="password_user" placeholder="Mot de passe"
ref={(input) => { this.passwordInput = input }}/>
<button type="submit">Login</button>
</form>
);
}
}
All data can be stored on React's state, but if you still need to have inputs on your form you can do something like this:
const handleSubmit = e => {
e.preventDefault();
const inputs = Object.values(e.target)
.filter(c => typeof c.tagName === 'string' && c.tagName.toLowerCase() === 'input')
.reduce((acc, curr) => ({ ...acc, [curr.name]: curr.value }), {});
setFormVals({ ...formVals, ...inputs });
}
See the demo below:
const Demo = () => {
const [formValues] = React.useState({});
const handleSubmit = e => {
e.preventDefault();
const inputs = Object.values(e.target)
.filter(c => typeof c.tagName === 'string' && c.tagName.toLowerCase() === 'input')
.reduce((acc, curr) => ({ ...acc, [curr.name]: curr.value }), {});
console.log(inputs);
}
return (
<form onSubmit={handleSubmit}>
<input name="name" placeholder="Name" value={formValues.name} />
<input name="email" placeholder="Email" value={formValues.email} />
<input name="hiddenInput" value="hiddenValue" type="hidden" />
<button type="submit">Submit</button>
</form>
);
}
ReactDOM.render(<Demo />, document.getElementById('demo'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>
<div id="demo"></div>
If you know what the inputs that you need you can do something like this:
const Demo = () => {
const formRef = React.useRef(null);
const [formValues, setFormValues] = React.useState({});
const handleChange = e => {
setFormValues({
...formValues,
[e.target.name]: e.target.value,
});
}
const handleSubmit = e => {
e.preventDefault();
setFormValues({ ...formValues, hiddenInput: formRef.current.hiddenInput.value });
}
return (
<form onSubmit={handleSubmit} ref={formRef}>
<input name="name" placeholder="Name" value={formValues.name} onChange={handleChange} />
<input name="email" placeholder="Email" value={formValues.email} onChange={handleChange} />
<input name="hiddenInput" value="hiddenValue" type="hidden" />
<button type="submit">Submit</button>
<pre>{JSON.stringify(formValues, null, 2)}</pre>
</form>
);
}
ReactDOM.render(<Demo />, document.getElementById('demo'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.0/umd/react-dom.production.min.js"></script>
<div id="demo"></div>
Answering your questions:
Since you know how to use component's state you may set the value as : <input type='text' value={this.state.foo} /> or even via props passing <input type='hidden' value={this.props.foo} />
You don't need to serialise anything at all. Use your component's local state or even a state container like Redux or Flux in order to pick the appropriate data. Take a look at this fairly simple example:
var SuperForm = React.createClass({
getInitialState() {
return {
name: 'foo',
email: 'baz#example.com'
};
},
submit(e){
e.preventDefault();
console.log("send via AJAX", this.state)
},
change(e,key){
const newState = {};
newState[key] = e.currentTarget.value;
this.setState(newState)
},
render: function() {
return (
<div>
<label>Name</label>
<input
onChange={(e) => this.change(e,'name')}
type="text"
value={this.state.name} />
<label>Email</label>
<input
onChange={(e) => this.change(e,'email')}
type="text"
value={this.state.email} />
<button onClick={this.submit}>Submit</button>
</div>
);
}});
Demo
AJAX is a set of web development techniques while Axios is a JavaScript framework. You may use jQuery, Axios or even vanilla JavaScript.
Related
I have my Formik form below (I'm new with formik). An this is the simple form which have two fields and makes api call using react-query (react -query works well).
But the problem is that formik state isSubmitting do not take effect when click. (Button do not start spinning, but if it is direct true, it works well)
I wonder what i'm missing? Why it has no effect? and How it could be solved?
Api Call:
const createUser = async ({name, password}: Record<string, string>) => {
return await axiosInstance.post(`users/create_user/`, {
name: name,
password: password,
});
};
React-query Mutation:
const createNewUser = useMutation(createUser, {
onSuccess: () => {
queryClient.refetchQueries(["getAllUsers"])
},
onError: (newUser) => {
console.log("onError", newUser);
}
Formik Form:
<Formik
initialValues={{ username: username, password: password }}
validateOnChange={false}
validateOnBlur={false}
onSubmit={(values, {setSubmitting, resetForm }) => {
setSubmitting(true)
createNewUser.mutate({
name: values.username,
password: values.password,
});
setSubmitting(false);
resetForm();
}}
>
{({ values, errors, isSubmitting, handleSubmit }) => (
<form onSubmit={handleSubmit}>
<div>
<label
htmlFor="Имя"
className="block text-900 font-medium mb-2"
>
</label>
<Field
type="text"
name="username"
className="w-full mb-3"
as={InputText}
/>
<Field
type="text"
name="password"
className="w-full mb-3"
as={InputText}
/>
<Button
label="save new user"
icon="pi pi-user"
className="w-full"
type="submit"
loading={isSubmitting} // to not take effect? why?
/>
</div>
</form>
Try using setTimeout, to setSubmitting(false) after few seconds not immediately like this:
setTimeout(() => setSubmitting(false), 2000);
Or, check if mutation is successfully executed, then setSubmitting to false
if(createNewUser.status == 'success' || createNewUser.status == 'error') {
setSubmitting(false);
}
Alternatively, without using formik isSubmitting you can use
createNewUser.isLoading
<Button
label="save new user"
icon="pi pi-user"
className="w-full"
type="submit"
loading={createNewUser.isLoading}
/>
Goal:
Retrieve data 'smartphones', by API, and apply it as a default selection in the input radio component for the react hook form.
Problem:
The code do not work that makes smartphones as a preselection in the input radio button.
However, if I make a change by using hard coding, it works but hard coding do not solve the case.
I don't know how to solve it.
Info:
*Using React TS and React hook form.
*Newbie in react TS and hook form.
Stackblitz:
https://stackblitz.com/edit/react-ts-z9cnzl
Thank you!
import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import './style.css';
type FormValues = {
lastName: string;
favShow: string;
};
export default function App() {
const [category, setCategory] = useState('');
React.useEffect(() => {
async function FetchData() {
var data = await fetch('https://dummyjson.com/products/1').then((res) => {
return res.json();
});
console.log(data.category);
setCategory(data.category);
}
FetchData();
}, []);
const [data, setData] = useState(null);
const { register, handleSubmit } = useForm<FormValues>({
defaultValues: {
lastName: 'asaaaaaaf',
favShow: category,
//favShow: 'smartphones',
},
});
const onSubmit = (data) => {
setData(data);
console.log('asdf');
};
return (
<React.Fragment>
<form onSubmit={handleSubmit(onSubmit)} className="form-container">
<h1 className="form-heading">React Hook Form Example</h1>
<input
{...register('lastName', { required: true })}
className="form-control"
type="text"
placeholder="Last name"
maxLength={15}
name="lastName"
/>
<br />
<br />
<label htmlFor="ted-lasso">
<input
{...register('favShow', { required: true })}
type="radio"
name="favShow"
value="smartphones"
id="smartphones"
/>{' '}
smartphones
</label>
<label htmlFor="got">
<input
{...register('favShow', { required: true })}
type="radio"
name="favShow"
value="GOT"
id="got"
/>
GOT
</label>
<br />
<br />
<button className="submit-btn" type="submit">
Submit
</button>
</form>
{data && <p className="submit-result">{JSON.stringify(data)}</p>}
</React.Fragment>
);
}
I got some help and the solution is:
Stackblitz:
https://stackblitz.com/edit/react-ts-m2s6ev?file=index.tsx
import React, { useState } from 'react';
import { useForm } from 'react-hook-form';
import './style.css';
type FormValues = {
lastName: string;
favShow: string;
};
export default function App() {
const [category2, setCategory2] = useState();
const [data, setData] = useState(null);
const { register, handleSubmit, resetField } = useForm<FormValues>({
defaultValues: {
lastName: '',
favShow: '',
},
});
React.useEffect(() => {
async function FetchData() {
var data = await fetch('https://dummyjson.com/products/1').then((res) => {
return res.json();
});
setCategory2(data);
}
FetchData();
}, []);
React.useEffect(() => {
if (category2) {
const obj = JSON.parse(JSON.stringify(category2));
console.log(obj);
resetField('lastName', { defaultValue: obj.discountPercentage });
resetField('favShow', { defaultValue: obj.category });
}
}, [resetField, category2]);
const onSubmit = (data) => {
setData(data);
};
return (
<React.Fragment>
<form onSubmit={handleSubmit(onSubmit)} className="form-container">
<h1 className="form-heading">React Hook Form Example</h1>
<input
{...register('lastName', { required: true })}
className="form-control"
type="text"
placeholder="Last name"
maxLength={15}
name="lastName"
/>
<br />
<br />
<label htmlFor="ted-lasso">
<input
{...register('favShow', { required: true })}
type="radio"
name="favShow"
value="smartphones"
id="smartphones"
/>{' '}
smartphones
</label>
<label htmlFor="got">
<input
{...register('favShow', { required: true })}
type="radio"
name="favShow"
value="GOT"
id="got"
/>
GOT
</label>
<br />
<br />
<button className="submit-btn" type="submit">
Submit
</button>
</form>
{data && <p className="submit-result">{JSON.stringify(data)}</p>}
</React.Fragment>
);
}
to update the complete object properties by using useState
pass textbox target value onchange event and change object properties using hooks
function ExampleObjectHooks() {
const [name, setname] = useState({ first: '', last: '' });
const onInputNameChange = (e) => {
setname({ first: e.target.value, last: e.target.value });
console.log(name);
}
return (
<div>
<form>
<input type="text" onChange={(e) => onInputNameChange(e)} ></input>
<input type="text" onChange={e => onInputNameChange(e)} ></input>
</form>
{name.first}{name.last}
</div>
);
}
Add an name attribute to each input field, and update the state using the name (key in the code). Node that you need to merge the state of each field by yourself. To so spread the previous state, and override the field you've just updated.
const { useState } = React;
function ExampleObjectHooks() {
const [name, setname] = useState({ first: '', last: '' });
const onInputNameChange = ({ target }) => {
const { name: key, value } = target;
setname(state => ({
...state,
[key]: value
}));
};
return (
<div>
<form>
<input name="first" type="text" onChange={onInputNameChange} ></input>
<input name="last" type="text" onChange={onInputNameChange} ></input>
</form>
{name.first} {name.last}
</div>
);
}
ReactDOM.render(
<ExampleObjectHooks />,
root
);
<script crossorigin src="https://unpkg.com/react#17/umd/react.development.js"></script>
<script crossorigin src="https://unpkg.com/react-dom#17/umd/react-dom.development.js"></script>
<div id="root"></div>
Here I am getting an error of handleSubmit function because ,here I am using this syntax 'function PostForm () ' instead of 'class PostForm extends Component {}',so what needs to be changed in order to work with handlesubmit function.
function PostForm () {
handleSubmit = (e) => {
e.preventDefault();
const title = this.getTitle.value;
const message = this.getMessage.value;
const data = {
id: new Date(),
title,
message
}
console.log(data)
}
return (
<div>
<h1>Create Post</h1>
<form onSubmit={this.handleSubmit}>
<input required type="text" ref={(input)=>this.getTitle = input}
placeholder="Enter Post Title"/>
<br /><br />
<textarea required rows="5" ref={(input)=>this.getMessage = input} cols="28"
placeholder="Enter Post" />
<br /><br />
<button>Post</button>
</form>
</div>
);
}
export default PostForm;
Since it's the function component you need to define handleSubmit as a function.
For example
const handleSubmit = (e) => {
...
}
I'm building a new portfolio site and I want it to have a contact form. The project is built with React and I had planned on using Formspree to add a contact form without a backend. Turns out Formspree no longer allows AJAX calls unless you're a paid subscriber.
Are there any alternatives for contact forms similar to Formspree? I had planned to do something like this but can't due to Formspree's limitations.
I know very little about backend programming and would prefer not to have to dive into Node/Express just for the sake of hooking up a contact form. Is this practical or would just adding a backend be easier at this point?
Hello you can use formcarry for this purpose.
Here is an example code for you:
import React from "react";
import axios from "axios"; // For making client request.
class Form extends React.Component {
constructor(props){
super(props);
this.state = {name: "", surname: "", email: "", message: ""};
}
handleForm = e => {
axios.post(
"https://formcarry.com/s/yourFormId",
this.state,
{headers: {"Accept": "application/json"}}
)
.then(function (response) {
console.log(response);
})
.catch(function (error) {
console.log(error);
});
e.preventDefault();
}
handleFields = e => this.setState({ [e.target.name]: e.target.value });
render() {
return (
<form onSubmit={this.handleForm}>
<label htmlFor="name">Name</label>
<input type="text" id="name" name="name" onChange={this.handleFields} />
<label htmlFor="surname">Surname</label>
<input type="text" id="surname" name="surname" onChange={this.handleFields} />
<label htmlFor="email">Email</label>
<input type="email" id="email" name="email" onChange={this.handleFields} />
<label htmlFor="message">Your Message</label>
<textarea name="message" id="message" onChange={this.handleFields}></textarea>
<button type="submit">Send</button>
</form>
);
}
}
export default Form;
As of Nov 2019 Formspree supports AJAX forms on the free plan. They recently did a 3 part tutorial series on building forms with React using Formspree for the examples. See: https://formspree.io/blog/react-forms-1/
Here's a snippet of code from part 3 of the above series. It's a simple contact for that performs client-side validation with Formik.
import React, { useState } from "react";
import axios from "axios";
import { Formik, Form, Field, ErrorMessage } from "formik";
import * as Yup from "yup";
const formSchema = Yup.object().shape({
email: Yup.string()
.email("Invalid email")
.required("Required"),
message: Yup.string().required("Required")
});
export default () => {
/* Server State Handling */
const [serverState, setServerState] = useState();
const handleServerResponse = (ok, msg) => {
setServerState({ok, msg});
};
const handleOnSubmit = (values, actions) => {
axios({
method: "POST",
url: "http://formspree.io/YOUR_FORM_ID",
data: values
})
.then(response => {
actions.setSubmitting(false);
actions.resetForm();
handleServerResponse(true, "Thanks!");
})
.catch(error => {
actions.setSubmitting(false);
handleServerResponse(false, error.response.data.error);
});
};
return (
<div>
<h1>Contact Us</h1>
<Formik
initialValues={{ email: "", message: "" }}
onSubmit={handleOnSubmit}
validationSchema={formSchema}
>
{({ isSubmitting }) => (
<Form id="fs-frm" noValidate>
<label htmlFor="email">Email:</label>
<Field id="email" type="email" name="email" />
<ErrorMessage name="email" className="errorMsg" component="p" />
<label htmlFor="message">Message:</label>
<Field id="message" name="message" component="textarea" />
<ErrorMessage name="message" className="errorMsg" component="p" />
<button type="submit" disabled={isSubmitting}>
Submit
</button>
{serverState && (
<p className={!serverState.ok ? "errorMsg" : ""}>
{serverState.msg}
</p>
)}
</Form>
)}
</Formik>
</div>
);
};
As an update in 2021 (not sure when it was introduced or changed) the standard react approach for formspree does not do any redirect and hides any AJAX details from you.
They have more info here - correct at tine of writing but worth checking as it updates quite regularly: https://help.formspree.io/hc/en-us/articles/360053108134-How-To-Build-a-Contact-Form-with-React
import React from 'react';
import { useForm, ValidationError } from '#formspree/react';
function ContactForm() {
const [state, handleSubmit] = useForm("contactForm");
if (state.succeeded) {
return <p>Thanks for joining!</p>;
}
return (
<form onSubmit={handleSubmit}>
<label htmlFor="email">
Email Address
</label>
<input
id="email"
type="email"
name="email"
/>
<ValidationError
prefix="Email"
field="email"
errors={state.errors}
/>
<textarea
id="message"
name="message"
/>
<ValidationError
prefix="Message"
field="message"
errors={state.errors}
/>
<button type="submit" disabled={state.submitting}>
Submit
</button>
</form>
);
}
export default ContactForm;
There are a few extra steps which are contained in the page above but this is the main contact from function