This question already has answers here:
Unable to access React instance (this) inside event handler [duplicate]
(19 answers)
Closed 7 years ago.
I was rewriting the React Tutorial in ES6, and got stuck in tutorial16.js. Whats the proper way to write this es5 in es6 format?
// tutorial16.js
var CommentForm = React.createClass({
getInitialState: function() {
return {author: '', text: ''};
},
handleAuthorChange: function(e) {
this.setState({author: e.target.value});
},
handleTextChange: function(e) {
this.setState({text: e.target.value});
},
render: function() {
return (
<form className="commentForm">
<input
type="text"
placeholder="Your name"
value={this.state.author}
onChange={this.handleAuthorChange}
/>
<input
type="text"
placeholder="Say something..."
value={this.state.text}
onChange={this.handleTextChange}
/>
<input type="submit" value="Post" />
</form>
);
}
});
Here is my CommentForm.jsx that I've written in ES6. If I try to type anything in the form, I get this message in the console: Uncaught TypeError: Cannot read property 'setState' of undefined
What I'm doing wrong?
import React from 'react';
class CommentForm extends React.Component {
constructor(props){
super(props);
this.state = { author: '', text: '' }
}
handleAuthorChange(e){
this.setState({author: e.target.value});
};
handleTextChange(e){
this.setState({text: e.target.value});
}
render(){
return(
<form className="commentForm">
<input type="text" placeholder="Your name" value={this.state.author} onChange={this.handleAuthorChange}/>
<input type="text" placeholder="Say something..." value={this.state.text} onChange={this.handleTextChange}/>
<input type="submit" value="Post" />
</form>
);
}
}
export default CommentForm;
You are missing binding onChange handlers to the instance. They are being fired in totally different context, where this doesn't point to your CommentForm.
It should be instead:
<input onChange={this.handleAuthorChange.bind(this)} type="text" placeholder="Your name" value={this.state.author} />
<input onChange={this.handleTextChange.bind(this)} type="text" placeholder="Say something..." value={this.state.text} />
With property initializers (ES6+) it may look like this:
class CommentForm extends React.Component {
state = {
author: '', text: ''
};
handleAuthorChange = (e) => {
this.setState({author: e.target.value});
};
handleTextChange = (e) => {
this.setState({text: e.target.value});
};
render() {
return <form className="commentForm">
<input
type="text"
placeholder="Your name"
value={this.state.author}
onChange={this.handleAuthorChange}
/>
<input
type="text"
placeholder="Say something..."
value={this.state.text}
onChange={this.handleTextChange}
/>
<input type="submit" value="Post" />
</form>
}
}
Related
This question already has answers here:
Handle change event of all input fields without using refs
(2 answers)
Closed 2 years ago.
I have several inputs ,Each of the inputs has its own value .How can I have a function for (onChange) all of them ?
For example
handleChange1(event) {
this.setState({value1: event.target.value});
}
handleChange2(event) {
this.setState({value2: event.target.value});
}
}
handleChange3(event) {
this.setState({value3: event.target.value});
}
<input type="text" value={this.state.value1} onChange={this.handleChange1} />
<input type="text" value={this.state.value2} onChange={this.handleChange2} />
<input type="text" value={this.state.value3} onChange={this.handleChange3} />
I just want to have one handleChange
When you need to handle multiple controlled input elements, you can add a name attribute to each element and let the handler function choose what to do based on the value of event.target.name.
For example:
handleInputChange(event) {
const target = event.target;
const value = target.type === 'checkbox' ? target.checked : target.value;
const name = target.name;
this.setState({
[name]: value
});
}
render() {
return (
<form>
<label>
value1:
<input
name="value1"
type="checkbox"
checked={this.state.value1}
onChange={this.handleInputChange} />
</label>
<br />
<label>
value2:
<input
name="value2"
type="number"
value={this.state.value2}
onChange={this.handleInputChange} />
</label>
<br />
<label>
value3:
<input
name="value3"
type="text"
value={this.state.value3}
onChange={this.handleInputChange} />
</label>
</form>
);
}
}
If you add a name to the input you can use that off of the event.
handleChange1(event) {
const {name, value} = event.target
this.setState({[name]: value});
}
<input name="inputone" type="text" value={this.state.value1} onChange={this.handleChange1} />
<input name="inputtwo" type="text" value={this.state.value2} onChange={this.handleChange2} />
<input name="inputthree" type="text" value={this.state.value3} onChange={this.handleChange3} />
You can simply do by using input name:
Code:
import React from "react";
import "./styles.css";
class MyComponent extends React.Component {
state = {
value1: "",
value2: "",
value3: ""
};
handleChange = (event) => {
this.setState({ [event.target.name]: event.target.value });
};
render() {
console.log(this.state);
return (
<>
<input
name="value1"
value={this.state.value1}
type="text"
value={this.state.value1}
onChange={this.handleChange}
/>
<input
name="value2"
value={this.state.value2}
type="text"
value={this.state.value2}
onChange={this.handleChange}
/>
<input
name="value3"
value={this.state.value3}
type="text"
value={this.state.value3}
onChange={this.handleChange}
/>
</>
);
}
}
export default function App() {
return (
<div className="App">
<h1>Hello CodeSandbox</h1>
<h2>Start editing to see some magic happen!</h2>
<MyComponent />
</div>
);
}
Demo: https://codesandbox.io/s/beautiful-brook-p46zs?file=/src/App.js:0-1092
i always do this by switch case
handleChange(event) {
switch (event.target.name) {
case 'name1':
this.setState({ name1: event.target.value });
break;
case 'name2':
this.setState({ name2: event.target.value });
break;
case 'name3':
this.setState({ name3: event.target.value });
break;
default:
break;
}
}
<input type="text" name="name1" value={this.state.value1} onChange={this.handleChange1} />
<input type="text" name="name2" value={this.state.value2} onChange={this.handleChange2} />
<input type="text" name="name3" value={this.state.value3} onChange={this.handleChange3} />
You can use react hooks useState for each field:
const [value1,setvalue1] = useState();
<input type="text" value={value1} onChange={(e)=>setvalue1(e.target.value)}/>
You still do have handle change to each input but you write less code.
You can also look here for more info about react hooks: https://reactjs.org/docs/hooks-state.html
If all inputs are same, I think we can render them dynamically so we don't need to repeat ourself and also make the code more clean.
I think we can have an array of inputs then render dynamically. By using closure, we can have one handleChange function for all inputs.
state={
inputValues: []
}
handleChange(index){
return (event)=>{
this.state.inputValues[index] = event.target.value;
this.setState({inputValues: this.state.inputValues})
}
}
render(){
return this.states.inputValues.map((inputValue, index)=>
<input type="text" value={inputValue} onChange={this.handleChange(index)} />
)
}
I am trying to catch 2 input field's value but none of the input fields is working.
when I comment second Input field than the first one works properly.
state = { zipcode: null, city: "" };
onFormSubmit = event => {
event.preventDefault();
//Callback
this.props.onEnter(this.state.zipcode);
};
handleChange = event => {
this.setState({ [event.target.name]: event.target.value });
};
render() {
return (
<div>
<form onSubmit={this.onFormSubmit}>
<input
type="number"
className={`form-control`}
placeholder="Enter ZIP code"
name="zipcode"
onChange={this.handleChange} />
<input
type="text"
className={`form-control`}
placeholder="Enter Zip-code"
name="city"
onChange={this.handleChange}/>
</form>
</div>
);
}
}
When I hit enter after entering a query in the first input field I get no output and no error.
I tried below code and it worked just fine. Maybe there is something wrong with your callback function. Because on form submission you are getting the correct values.
class Hello extends React.Component {
constructor(props) {
super(props);
this.state = {
zipcode: null,
city: ""
}
}
onFormSubmit = event => {
event.preventDefault();
//Callback
console.log(this.state);
};
handleChange = event => {
this.setState({ [event.target.name]: event.target.value });
}
render() {
return (
<div>
<form onSubmit={this.onFormSubmit}>
<input
type="number"
className={`form-control`}
placeholder="Enter ZIP code"
name="zipcode"
onChange={this.handleChange} />
<input
type="text"
className={`form-control`}
placeholder="Enter Zip-code"
name="city"
onChange={this.handleChange}/>
<input type="submit" value="submit" />
</form>
</div>
);
}
}
ReactDOM.render(
<Hello name="World" />,
document.getElementById('container')
);
Here is the jsfiddle link with your code. Check in the inspect element after clicking on the submit button.
It works.
https://jsfiddle.net/t4o0xawr/1/
I'm building a check builder, I have multiple Parent components (forms) that display their inputs on a Child component (check layout).
This is my parent component:
import React from 'react';
import './../App.css';
import Check from './Check';
class BusinessAddress extends React.Component {
constructor(props) {
super(props);
this.state = {text: {
name: 'BusinessAddress',
a: '',
b: '',
c: '',
d: '',
e: '',
f: '',
g: '',
h: ''
}};
}
handleComponentName = name => {
//console.log('handleComName', name)
return this.state.name === name;
}
handleChange(property, event) {
console.log(event.target.value);
const text = {...this.state.text};
text[property] = event.target.value;
this.setState({text: text});
}
handleSubmit(event) {
console.log(this.state.text.e);
}
render() {
return (
<div>
<div className="form-box">
<h3>Business Address</h3>
<label>Business Name</label>
<input type="text" placeholder="Business Name" value={this.state.text.a} onChange={this.handleChange.bind(this, 'a')} maxLength="30" />
<label>Name Line 2</label>
<input type="text" placeholder="Business Name Line 2" value={this.state.text.b} onChange={this.handleChange.bind(this, 'b')} maxLength="90" />
<label>Street Address</label>
<input type="text" placeholder="Street Address" value={this.state.text.c} onChange={this.handleChange.bind(this, 'c')} maxLength="30" />
<label>Address Line 2</label>
<input type="text" placeholder="Street Address Line 2" value={this.state.text.d} onChange={this.handleChange.bind(this, 'd')} maxLength="30" />
<label>City</label>
<input type="text" className="short" placeholder="City" value={this.state.text.e} onChange={this.handleChange.bind(this, 'e')} maxLength="30" />
<label>State</label>
<input type="text" className="short" placeholder="State" value={this.state.text.f} onChange={this.handleChange.bind(this, 'f')} maxLength="30" />
<label>Postal</label>
<input type="text" className="short" placeholder="Postal" value={this.state.text.g} onChange={this.handleChange.bind(this, 'g')} maxLength="30" />
<label>Phone (optional)</label>
<input type="text" className="short" placeholder="Phone" value={this.state.text.h} onChange={this.handleChange.bind(this, 'h')} maxLength="30" />
</div>
<Check data={this.state.text} handleParent={this.handleComponentName}/>
</div>
)
}
}
export default BusinessAddress;
This is my child component:
import React from 'react';
import './../App.css';
export class Check extends React.Component {
constructor(props) {
super(props);
this.state = {}
}
render() {
const data = Object.values(this.props.data);
if(this.props.handleParent('BusinessAddress')) {
}
return (
<div>
{ data.map((item, index) => <li key={index}>{item}</li>) }
<div id="Address"></div>
<div id="Bank-Info"></div>
</div>
)
}
}
export default Check;
I'm trying to map the data to a specific div based on which parent the data is coming from. Right now all that I'm getting from the child is the returned function, but no return value?
Thanks in advance!
<input type="text" placeholder="Business Name" value={this.state.text.a} onChange={this.handleChange.bind(this, 'a')} maxLength="30" />
Change this to this
<input type="text" placeholder="Business Name" value={this.state.text.a} onChange={(e) => this.handleChange(e, 'a')} maxLength="30" />
also change this
handleComponentName = name => {
//console.log('handleComName', name)
return this.state.name === name; }
to
this.state.text.name === name;
here is the demo
Try binding the onchange like
onChange={(event) => this.handleChange('h', event)}
I am new to react… my handle change event is not working while typing text into an input. How do I go about fixing that? I want to handle both inputs with the same handle change.
import React from 'react'
import TextField from 'material-ui/TextField'
class Settings extends React.Component {
constructor(props) {
super(props)
this.state = {
first_name:'',
last_name:''
}
}
handleChange(e){
var first_name = e.target.first_name
var last_name = e.target.last_name
var state = this.state
state[first_name] = e.target.value
state[last_name] = e.target.value
this.setState(state)
}
render() {
return (
<div>
<TextField hint text="First Name" id="user_first_name" floatingLabelFixed="editprofile" onChange={this.handleChange.bind(this)} name="user[first_name]" size="30" type="text" value={this.state.first_name} />
<TextField hint text="Last Name" id="user_last_name" floatingLabelFixed="editprofile" name="user[last_name]" onChange={this.handleChange.bind(this)} size="30" type="text" value={this.state.last_name} />
</div>
)
}
}
Based on id you should update the state and not both on them together. Try the below method. Also change the ids
import React from 'react'
import TextField from 'material-ui/TextField'
class Settings extends React.Component {
constructor(props) {
super(props)
this.state = {
first_name:'',
last_name:''
}
}
handleChange(e){
this.setState({[e.target.id]: e.target.value});
}
render() {
return (
<div>
<TextField hint text="First Name" id="first_name" floatingLabelFixed="editprofile" onChange={this.handleChange.bind(this)} name="user[first_name]" size="30" type="text" value={this.state.first_name} />
<TextField hint text="Last Name" id="last_name" floatingLabelFixed="editprofile" name="user[last_name]" onChange={this.handleChange.bind(this)} size="30" type="text" value={this.state.last_name} />
</div>
)}
}
as you're using material-ui/TextField component updating state by target.id can't work, because TextField component doesn't pass your id to its input, so you can do it by adding second parameter to your handleChange function, like this:
import React from 'react'
import TextField from 'material-ui/TextField'
class Settings extends React.Component {
constructor(props) {
super(props)
this.state = {
first_name:'',
last_name:''
}
}
handleChange(value, param){
this.setState({[param]: value});
}
render() {
return (
<div>
<TextField hint text="First Name" id="first_name" floatingLabelFixed="editprofile" onChange={(e) => this.handleChange(e.target.value, 'first_name')} name="user[first_name]" size="30" type="text" value={this.state.first_name} />
<TextField hint text="Last Name" id="last_name" floatingLabelFixed="editprofile" name="user[last_name]" onChange={(e) => this.handleChange(e.target.value, 'last_name')} size="30" type="text" value={this.state.last_name} />
</div>
)}
}
I think, issue is you are updating both the fields by the same value, write it like this:
handleChange(e){
var obj = {}
obj[e.target.name] = e.target.value
this.setState(obj);
}
And assign the same name as the state variable names, like this:
<TextField ... name='first_name' value={this.state.first_name} onChange={this.handleChange.bind(this)}/>
<TextField ... name='last_name' value={this.state.last_name} onChange={this.handleChange.bind(this)} />
Use this:
class Settings extends React.Component {
constructor(props) {
super(props)
this.state = {
first_name:'',
last_name:''
}
}
handleChange(e){
let obj = {};
obj[e.target.name] = e.target.value;
this.setState(obj);
}
render() {
return (
<div>
<TextField hintText="First Name" id="first_name" floatingLabelFixed="editprofile" onChange={this.handleChange.bind(this)} name="first_name" size="30" type="text" value={this.state.first_name} />
<TextField hinText="Last Name" id="last_name" floatingLabelFixed="editprofile" name="last_name" onChange={this.handleChange.bind(this)} size="30" type="text" value={this.state.last_name} />
</div>
)}
}
class Settings extends React.Component {
constructor(props) {
super(props)
}
handleChange=(e)=>{
const {name,value}=e.target;
this.setState({[name]=value});
}
render() {
return (
<div>
<TextField hintText="First Name" floatingLabelFixed="editprofile" onChange={this.handleChange} name="first_name" size="30" type="text" />
<TextField hinText="Last Name"floatingLabelFixed="editprofile" name="last_name" onChange={this.handleChange} size="30" type="text"/>
</div>
)}
}
I have two fields in the form, but i am not able to post the data to the server. I know how to submit single filed but how do i submit multiple field in the form.
below is the code of 2 fields
class Createstudent extends React.Component {
constructor(props) {
super(props);
this.state = {name: '',
age:''
};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({name: event.target.value});
this.setState({age:event.target.value});
}
handleSubmit(event) {
alert(this.state.name);
axios.post('/create',{values:this.state.name,ages:this.state.age})
.then(function(response){
console.log(response);
})
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.name} onChange={this.handleChange} />
</label>
<label>
Age:
<input type="text" value={this.state.age} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Reason is you are updating both the fields with the same value, on change of any one, update the specific field, it will work, try this:
handleChange(event) {
if(event.target.name == 'name')
this.setState({name: event.target.value});
else
this.setState({age: event.target.value});
}
or
handleChange(event) {
this.setState({[event.target.name]: event.target.value});
}
Add name attr to input field to identify them uniquely, Use this render method:
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" name='name' value={this.state.name} onChange={this.handleChange} />
</label>
<label>
Age:
<input type="text" name='age' value={this.state.age} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
Check the jsfiddle: https://jsfiddle.net/dp0an79f/
I have changed the code like this.And its working.
import React from 'react';
import axios from 'axios';
class Createstudent extends React.Component {
constructor(props) {
super(props);
this.state = {name: '',
age:''
};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleSubmit(event) {
alert(this.state.name);
axios.post('/create',{values:this.state.name,ages:this.state.age})
.then(function(response){
console.log(response);
})
}
componentDidMount(){
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.name} onChange={e => this.setState({ name: e.target.value })} />
</label>
<label>
Age:
<input type="text" value={this.state.age} onChange={e => this.setState({ age: e.target.value })} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}