What is better?
I have a form with 10 inputs.
Should I use this.input.value or handle change and store it in state?
handleChange(e) {
this.setState({input: e.target.value});
}
...
<input type="text" value={this.state.input} onChange={this.handleChange} />
or
onSubmit() {
const inputValue = this.input.value;
...
}
...
<input type="text" ref={(input) => {this.input = input;}} />
From the documentation:
When to Use Refs
There are a few good use cases for refs:
Managing focus, text selection, or media playback.
Triggering imperative animations.
Integrating with third-party DOM libraries.
Avoid using refs for anything that can be done declaratively.
Setting up controlled inputs is kind of a pain, but I use this pattern to make it a little easier.
Create one onChange event handler for ALL inputs:
handleInputChange(e){
const target = e.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
Then, for your inputs, be sure to give it a name that matches a key in your state to update.
render() {
const { firstName, lastName, email, acceptTerms } = this.state;
return (
<form>
<input name="firstName" onChange={this.handleInputChange} value={firstName} />
<input name="lastName" onChange={this.handleInputChange} value={lastName} />
<input name="email" onChange={this.handleInputChange} value={email} />
<input type="checkbox" name="acceptTerms" onChange={this.handleInputChange} checked={acceptTerms} />
</form>
)
}
Related
Why can't I put a value in the input? The problem is: I need to put a 'name' in <Form.Item> to apply the rules. Without that, the rules will not be able to work, but if you remove the name="userName" from <Form.Item the value appears at the input.
How can i solve that?
<Form autoComplete="off" layout="vertical" onFinish={handleFinish}>
<Form.Item name="userName" rules={getTextRule('name')}>
<Input value={fields?.firstName} name="firstName" onChange={(e) => {
handleInputChange(e)
}} />
</Form.Item>
</Form.Item>
simple we can code like
const [text,setText] = useState('')
return(
<input type='text' value={text} onChange={e=>setText(e.target.value)}/>
)
If you use the form you can let Ant Form manage the state by removing the value & the onChange props on the <Input />.
Else if you manage the state by yourself make sure to get the value from the e.target.value.
ex:
const [fields, setFields] = useState({})
const handleOnChange = (e) => {
setFields((state) => {
...state,
[e.target.name]: e.target.value,
})
}
return (
<Input
name="firstName"
value={fields.firstName}
onChange={handleOnChange}
/>
)
I am going to update the form with each keystroke with useState Hook this way I have to add an onChange event listener plus a function for each input and as you can imagine it's going to be lots of functions how can I avoid repeating myself?
function firstNamInput(){
}
function lastNameInput(){
}
function emailInput(){
}
function phoneInput(){
}
function addressInput(){
}
function genderInput(){
}
function jobInput(){
}
function ageInput(){
}
in react we try to collect form data on every keystroke but in the past, we used to collect form data when submit clicked. so because of this new approach, we have to listen for every keystroke on every input! isn't this crazy? yes, kind of but there is a way to go around I am going to explain it to you :
first I am going to talk about Rules you have to know about inputs:
we are going to use a useState Hook and we pass an object to it which contain:
a property for every input that's single
a property for group inputs (for example if there is checkboxes for gender we create only one property for gender)
what attributes every input should have?
name (it's going to be equal to its property in the useState)
value or checked (as a rule of thumb if the inputs gets true or false its usually checked vice versa )
onChange event
so let's create useState I am going to have a total of 7 properties in the object:
const [formData, setFormData] = React.useState(
{
firstName: "",
lastName: "",
email: "",
comments: "",
isFriendly: true,
employment: "",
favColor: ""
}
)
we need to create a function for the onChange event i am going to make it as reusable as possible it's going to get form data from each input and update it in our Hook.
function handleChange(event) {
const {name, value, type, checked} = event.target
setFormData(prevFormData => {
return {
...prevFormData,
[name]: type === "checkbox" ? checked : value
}
})
}
now we are going to add inputs look at note 2 again and now you are ready
import React from "react"
export default function Form() {
const [formData, setFormData] = React.useState(
{
firstName: "",
lastName: "",
email: "",
comments: "",
isFriendly: true,
employment: "",
favColor: ""
}
)
function handleChange(event) {
const {name, value, type, checked} = event.target
setFormData(prevFormData => {
return {
...prevFormData,
[name]: type === "checkbox" ? checked : value
}
})
}
function handleSubmit(event) {
event.preventDefault()
// submitToApi(formData)
console.log(formData)
}
return (
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="First Name"
onChange={handleChange}
name="firstName"
value={formData.firstName}
/>
<input
type="text"
placeholder="Last Name"
onChange={handleChange}
name="lastName"
value={formData.lastName}
/>
<input
type="email"
placeholder="Email"
onChange={handleChange}
name="email"
value={formData.email}
/>
<textarea
value={formData.comments}
placeholder="Comments"
onChange={handleChange}
name="comments"
/>
<input
type="checkbox"
id="isFriendly"
checked={formData.isFriendly}
onChange={handleChange}
name="isFriendly"
/>
<label htmlFor="isFriendly">Are you friendly?</label>
<br />
<br />
<fieldset>
<legend>Current employment status</legend>
<input
type="radio"
id="unemployed"
name="employment"
value="unemployed"
checked={formData.employment === "unemployed"}
onChange={handleChange}
/>
<label htmlFor="unemployed">Unemployed</label>
<br />
<input
type="radio"
id="part-time"
name="employment"
value="part-time"
checked={formData.employment === "part-time"}
onChange={handleChange}
/>
<label htmlFor="part-time">Part-time</label>
<br />
<input
type="radio"
id="full-time"
name="employment"
value="full-time"
checked={formData.employment === "full-time"}
onChange={handleChange}
/>
<label htmlFor="full-time">Full-time</label>
<br />
</fieldset>
<br />
<label htmlFor="favColor">What is your favorite color?</label>
<br />
<select
id="favColor"
value={formData.favColor}
onChange={handleChange}
name="favColor"
>
<option value="red">Red</option>
<option value="orange">Orange</option>
<option value="yellow">Yellow</option>
<option value="green">Green</option>
<option value="blue">Blue</option>
<option value="indigo">Indigo</option>
<option value="violet">Violet</option>
</select>
<br />
<br />
<button>Submit</button>
</form>
)
}
Hi everybody Tring to make a form with Form provided by bootstap but it doesn't work.
If I insert value it doesn't let me type, without value I digit but I can't get the value.
(I have also a Gatsby theme activated)
const StandAdd = () => {
const [item, setItem] = useState({
title: "",
kindof: "",
website: "",
image01: "",
image02: "",
image03: "",
})
const { title, kindof, website, image01, image02, image03 } = item
const handleInputChange = event => {
event.preventDefault()
setItem({ ...item, [event.target.name]: event.target.value })
}
const handleSubmit = event => {
event.preventDefault()
alert(`${title} ${item} ${website}`) // always empty I gat get anything
}
return (
<Layout>
<form onSubmit={handleSubmit}>
<Form>
<Form.Group controlId="title">
{/* <Form.Label>Email address</Form.Label> */}
<Form.Control
value={titlet} // <-- this blocks the typing
type="text"
placeholder="Enter Stand's Name"
onChange={handleInputChange}
/>
</Form.Group>
<Button variant="primary" type="submit">
Submit
</Button>
</Form>
</form>
</Layout>
)
}
export default StandAdd
Any idea?
The issue is here:
<Form.Control
value="title" // <-- this blocks the typing
type="text"
placeholder="Enter Stand's Name"
onChange={handleInputChange}
/>
here you have to provide the name attribute so that your code:
setItem({ ...item, [event.target.name]: event.target.value })
will get some value in event.target.name.
So after adding name the code will be like:
<Form.Control
type="text"
name="title" <---- name added here
placeholder="Enter Stand's Name"
onChange={handleInputChange}
/>
And don't provide a hard-coded value to input like this:
value="title"
instead use defaultValue for providing an initial value.
I think you need to provide name attribute to <Form.Control> component.
I need your help, I'm trying to use a form from react-strap and for some reason I get this error:
Warning: A component is changing a controlled input of type password to be uncontrolled. Input elements should not switch from controlled to uncontrolled (or vice versa). Decide between using a controlled or uncontrolled input element for the lifetime of the component
this is my code.
everything is controlled but I still get the error, can anyone spot my mistake?
const LoginForm = () => {
const [formData, setFormData] = useState({
email: " ",
password: " "
});
const onChange = e => {
setFormData({
[e.target.name]: e.target.value
});
};
const onSubmit = e => {
e.preventDefault();
console.log("email password are", formData.email, formData.password);
loginUser(formData.email, formData.password);
};
return (
<Form onSubmit={onSubmit}>
<FormGroup>
<h1>Login</h1>
</FormGroup>
<FormGroup>
<Label for="Email">Email</Label>
<Input
type="email"
name="email"
id="Email"
placeholder="example#mail.com"
onChange={onChange}
value={formData.email}
/>
</FormGroup>
<FormGroup>
<Label for="Password">Password</Label>
<Input
type="password"
name="password"
id="Password"
placeholder="password"
onChange={onChange}
value={formData.password}
/>
</FormGroup>
<Button>Submit</Button>
</Form>
);
};
Ok I found the error, I didn't spread the last answer, so by inputting password I overwritten my email, the proper on change should be this:
const onChange = e => {
setFormData({ ...formData, [e.target.name]: e.target.value });
};
I am new to react and redux technology. now started building an application that contains several redux forms. We want to submit simple form with values.
For ex: login form
Username : text input field
Password: text input field
Submit button
After entering values in fields and click on submit button i want to get the username and password field values in object or json data .. so that I can store it to my server with POST method.
Right now we are using handleSubmit(), but data is not coming as object
1 - The best practice to deal with input values are making them controlled. Which means :
Instead of
<input type='password' />
You do :
<input
type='password'
value={password}
onChange={ event => myInputHandler( event.target.value ) }
/>
The value might come from your state, redux state or as a props etc.
Your handler function differs according to where you store it.
I will give you an example with react state :
<input
type='password'
value={this.state.password}
onChange={ event => this.setState({ password : event.target.value }) }
/>
So whenever someone types, your onChange handler will be called, so that your react state will update with the input ( event.target.value ).
2 - If you need these values when a user submits, then you need to wrap these input fields within a form element and attach a onSubmit handler.
onSubmitHandler( event ){
event.preventDefault()
let password = this.state.password
// use password or other input fields, send to server etc.
}
<form onSubmit={ event => this.onSubmitHandler(event) }>
<input
type='password'
value={this.state.password}
onChange={ event => this.setState({ password : event.target.value }) }
/>
</form>
Hope you get what you need.
If you are using redux to store state then use redux-from then use redux from
import React from 'react'
import {Field, reduxForm} from 'redux-form'
const SimpleForm = props => {
const {handleSubmit, submitting} = props return (
<form onSubmit={handleSubmit(e=>console.log('your form detail here', e))}>
<div>
<label>First Name</label>
<div>
<Field name="firstName" component="input" type="text" placeholder="First Name" />
</div>
</div>
<div>
<label>Last Name</label>
<div>
<Field name="lastName" component="input" type="text" placeholder="Last Name" />
</div>
</div>
<div>
<button type="submit" disabled={pristine || submitting}>Submit</button>
</div>
</form>
) }
export default reduxForm({ form: 'simple'})(SimpleForm)
Go here for more detail
https://redux-form.com
I put the name of the input as the key that I want to use.
Then each time the input changes I destructure the event passed to the onChange function, and I use the name,value to update the state.
On form submit make sure to use preventDefault(); in order to avoid the page refreshing.
import React, { Component } from 'react'
class FormExample extends Component {
constructor(props){
super(props)
this.state = {
formData: {}
}
}
handleInputChange = ({ target: { name,value } }) => {
this.setState({
formData: {
...this.state.formData,
[name]: value
}
})
}
handleFormSubmit = e => {
e.preventDefault()
// This is your object
console.log(this.state.formData)
}
render() {
return(
<div>
<Form
handleSubmit={this.handleFormSubmit}
handleChange={this.handleInputChange}
/>
</div>
)
}
}
const Form = ({ handleSubmit, handleChange }) => (
<form onSubmit={handleSubmit}>
<input onChange={handleChange} name="username" type="text" placeholder="Username" />
<input onChange={handleChange} name="password" type="password" placeholder="Password" />
<button>Submit</button>
</form>
)
export default FormExample