I am learning react. I have created a form and on submit I want to render another(Info here) component and I am unable to do so.here is my code example.
App.js
class App extends React.Component {
constructor(props) {
super(props)
this.state = { username: '' }
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(event) {
this.setState({ value: event.target.value })
}
handleSubmit(event) {
alert(this.state.username)
event.preventDefault()
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<input
type="text"
value={this.state.username}
onChange={this.handleChange}
/>
<button type="button" class ="button" value="Info" onClick={this.handleSubmit} component = {Summary}>Summary</button>
</form>
)
}
}
Info.js
class Info extends React.Component{
{more logic and code for this component}
render(){
return (<h1>Welcome To Info</h1>)
}
}
export default Info
You can do it this way
class App extends React.Component {
constructor(props) {
super(props)
this.state = { username: '', showInfo: false }
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(event) {
this.setState({ value: event.target.value })
}
handleSubmit(event) {
alert(this.state.username)
event.preventDefault()
this.setState({showInfo: true});
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input
type="text"
value={this.state.username}
onChange={this.handleChange}
/>
<button type="button" class ="button" value="Info" onClick={this.handleSubmit} component = {Summary}>Summary</button>
</form>
{this.state.showInfo ? <Info /> : null}
</div>
)
}
}
function Info(props){
return <h3>{props.username}</h3>
}
class App extends React.Component {
constructor(props) {
super(props)
this.state = { username: '' }
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange =(event)=> {
this.setState({ username: event.target.value })
}
handleSubmit(event) {
alert(this.state.username)
event.preventDefault()
}
render() {
return (
<div>
<form onSubmit={this.handleSubmit}>
<input
type="text"
value={this.state.username}
onChange={this.handleChange}
/>
<button type="button" class ="button" value="Info"
onClick={this.handleSubmit}>Summary</button>
</form>
<Info {...this.state}/>
</div>
)
}
}
Related
I want to create a form and save some values.
I have this constructor code :
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);}
and have handleChange function:
handleChange(event) {
this.setState({value: event.target.value});}
and have handleSubmit function:
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();}
the handleSubmit function there is error :
Property 'value' does not exist on type '{}'.ts(2339).
How to slove it ?
Here is full code:
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
This is the error
Since you are using typescript you need to do something like this. Have a look at this stackBlitz
https://stackblitz.com/edit/react-ts-gfcdog
import React from "react";
interface State{
value? : string
}
export default class NameForm extends React.Component<{},State> {
constructor(props: any) {
super(props);
this.state = { value: "" };
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event: any) {
this.setState({ value: event.target.value });
}
handleSubmit(event: any) {
alert("A name was submitted: " + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input
type="text"
value={this.state.value}
onChange={this.handleChange}
/>
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Is there a way to pass form data from child component to Parent component, where submit buttons have been kept in parent component.
NOTE: - I don't want to use ref for this as the ref would be waste of so much of memory and I might have 6-7 children in the parent.
I have created a similar situation to show what I am stuck on.
class FirstChildForm extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
render() {
return (
<div className="form">
<input type="text" placeholder="Enter your name..." />
<input type="password" placeholder="Enter password" />
</div>
)
}
}
class SecondChildForm extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
render() {
return (
<div className="form">
<input type="text" placeholder="Enter your name..." />
<input type="password" placeholder="Enter password" />
</div>
);
}
}
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
handleSubmit = () => {
}
render() {
return (
<div className="parent">
<FirstChildForm />
<SecondChildForm />
<button onClick={this.handleSubmit}> Submit</button>
</div>
)
}
}
Sure, the concept is called lifting the state up. Basically, your <App /> component would hold the data from both components. I'm going to simplify a bit, but you should understand what I'm doing.
FirstChildForm.js
<input type="text" name="username" onChange={e => props.updateData('user', e.target.value)}
SecondChildForm.js
<input type="password" name="password" onChange={e => props.updateData('pass', e.target.value)}
App.js
export default class App extends React.Component {
constructor() {
super();
this.state = {
user: '',
pass: '',
};
}
handleSubmit = () => {};
updateData = (target, value) => {
this.setState({ [target]: value });
};
render() {
return (
<div className="parent">
<FirstChildForm updateData={this.updateData} />
<SecondChildForm updateData={this.updateData} />
<button onClick={this.handleSubmit}> Submit</button>
</div>
);
}
}
The <App /> component is the source of truth. Please note:
By lifting the state up, <FirstChildForm /> and <SecondChildForm /> don't need to be class based components anymore, they can be functional components. If you want them to remain class based for whatever reason, change props.updateData to this.props.updateData, else it won't work.
The parent is where we define the function, the child is where we execute it, sending data to parent, basically!
by passing a function to the child component as props and passing the child component's state as parameter to the function
as i dont know what you exactly want to code inside but only to understand checkout
following example
parent:
export default class App extends React.Component {
constructor(props){
super(props);
this.state = {
data: []
}
}
handleSubmit = () => {
}
handleData = (newData) => {
this.setState({data: newData});
}
render(){
return (
<div className="parent">
<FirstChildForm / >
<SecondChildForm onSelectData={this.handleData}/>
<button onClick={this.handleSubmit}> Submit</button>
</div>
)
}
}
Child:
class SecondChildForm extends React.Component{
constructor(props){
super(props);
this.state = {
data:'hello'
}
}
handleDataChange: function () {
var newData = this.state.data
this.props.onSelectData(newData);
},
render(){
return (
<div className="form">
<input type="text" placeholder="Enter your name..." />
<input type="password" placeholder="Enter password" />
<button onclick={this.handleDataChange}>submit</button>
</div>
);
}
}
You will have to pass a function down to your children components. Your children will now be able to bind this function from their props to the given fields.
class FirstChildForm extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
render() {
return (
<div className="form">
<input type="text" placeholder="Enter your name..." onChange={this.props.dataChanged('name')}/>
<input type="password" placeholder="Enter password" onChange={this.props.dataChanged('password')}/>
</div>
)
}
}
class SecondChildForm extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
render() {
return (
<div className="form">
<input type="text" placeholder="Enter your name..." onChange={this.props.dataChanged('name')}/>
<input type="password" placeholder="Enter password" onChange={this.props.dataChanged('password')}/>
</div>
);
}
}
export default class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: []
}
}
handleChange = form => field => ev => {
this.setState(prev => ({ [form]: { ...prev[form], [field]: ev.target.value } }))
}
The resulting state of your parent will have the following structure :
{
'firstForm': {
'name': '',
'password': ''
},
'secondForm': {
'name': '',
'password': ''
}
}
I am fairly new to React coming from a JS & Java background. I am still understanding react state properties and have two code samples, one which compiles and one which does not. In the first, I establish the class' state as having one variable str and I work with this variable. This code does not work. In the second, the variable is named value, and it works. Is it not possible to have a variable under a different name or more than one variable in react? Thank you!!
Side Note: The term "works" in this context is the difference between being able to type into the text field or not.
Form Code (Works):
class SomeOtherForm extends React.Component {
constructor(props) {
super(props);
this.state = {
str: '',
};
this.handleSubmit = this.handleSubmit.bind(this);
}
handleValueChanged(event) {
this.setState({str: event.target.value});
}
handleSubmit(event) {
alert('Y.. ' + this.state.str);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type='text' value={this.state.str} onChange={this.handleChange}/>
</label>
<input type='submit' value='Submit'/>
</form>
);
}
}
Form Code (Doesn't Work):
class NameForm extends React.Component {
constructor(props) {
super(props);
this.state = {value: ''};
this.handleChange = this.handleChange.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
}
handleChange(event) {
this.setState({value: event.target.value});
}
handleSubmit(event) {
alert('A name was submitted: ' + this.state.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" value={this.state.value} onChange={this.handleChange} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
In SomeOtherForm there are a few mishaps:
You're calling this.handleChange for the onChange event, but this method doesn't exist (it needs to be changed from handleValueChanged to handleChange)
You haven't bound both handlers to the constructor (you need to add this.handleChange = this.handleChange.bind(this);)
Fixed:
class SomeOtherForm extends React.Component {
constructor(props) {
super(props)
this.state = { str: '' }
this.handleChange = this.handleChange.bind(this)
this.handleSubmit = this.handleSubmit.bind(this)
}
handleChange(event) {
this.setState({
str: event.target.value
})
}
handleSubmit(event) {
event.preventDefault()
alert(`Yo shit isssss.. ${this.state.str}`)
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input
type='text'
value={this.state.str}
onChange={this.handleChange} />
</label>
<input
type='submit'
value='Submit'/>
</form>
)
}
}
In the first example you named the function handleValueChanged NOT handleChange...
This will fix your problem:
<input type='text' value={this.state.str} onChange={this.handleValueChanged}/>
As a side note state in react is an objectand thats it. So referring to state like this
I establish the class' state as having one variable str and I work
with this variable
Isnt actually technically accurate and makes things sound more confusing than they are.
It's totally possible manage different variables in state.
constructor (props) {
super(props)
this.state = {
name: '',
lastname: ''
}
this.handleSubmit = this.handleSubmit.bind(this)
this.handleChange = this.handleChange.bind(this)
}
handleSubmit (event) {
event.preventDefault()
console.log(this.state)
}
handleChange (event) {
const { name, value } = event.target
this.setState({
[name]: value
})
}
render () {
<form onSubmit={this.handleSubmit}>
<input
name='name'
value={this.state.name}
onChange={this.handleChange}
/>
<input
name='lastname'
value={this.state.lastname}
onChange={this.handleChange}
/>
</form>
}
Pay attention to the name of the inputs they should be the same as the variables in your state.
This is how I'm currently handling the scenario with two input boxes. As a separate update method for each one. Can/should this be done with a single handleChange method instead?
https://codepen.io/r11na/pen/bZKOpj?editors=0011
class App extends React.Component {
constructor(props) {
super(props);
this.handleChange1 = this.handleChange1.bind(this);
this.handleChange2 = this.handleChange2.bind(this);
this.state = {
name1: '',
name2: ''
};
};
handleChange1(e) {
this.setState({
name1: e.target.value
});
};
handleChange2(e) {
this.setState({
name2: e.target.value
});
};
render() {
return (
<div class="row column">
<Label name={this.state.name1}/>
<Input onChange={this.handleChange1} />
<Label name={this.state.name2}/>
<Input onChange={this.handleChange2} />
</div>
);
};
}
const Label = props => (
<p {...props}>Hello: <span className="label-name">{props.name}</span></p>
);
const Input = props => (
<input placeholder="Enter your name" {...props} type="text" />
);
ReactDOM.render(<App />, document.getElementById('app'))
Can/should this be done with a single handleChange method instead?
You can simplify your code like so.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
name1: '',
name2: ''
};
};
handleChange(e, name) {
this.setState({ [name]: e.target.value });
};
render() {
return (
<div class="row column">
<Label name={this.state.name1}/>
<Input onChange={ (e) => this.handleChange(e, 'name1') } />
<Label name={this.state.name2}/>
<Input onChange={ (e) => this.handleChange(e, 'name2') } />
</div>
);
};
}
Example
Thanks #Alik that mentioned about eslint rule jsx-no-bind,
A bind call or arrow function in a JSX prop will create a brand new
function on every single render. This is bad for performance, as it
will result in the garbage collector being invoked way more than is
necessary.
Following this rule you can change your code like
class App extends React.Component {
constructor(props) {
super(props);
this.onChange = {
name1: this.handleChange.bind(this, 'name1'),
name2: this.handleChange.bind(this, 'name2'),
}
this.state = {
name1: '',
name2: ''
};
};
handleChange(name, event) {
this.setState({ [name]: event.target.value });
};
render() {
return (
<div class="row column">
<Label name={this.state.name1}/>
<Input onChange={ this.onChange.name1 } />
<Label name={this.state.name2}/>
<Input onChange={ this.onChange.name2 } />
</div>
);
};
}
Example
I tried to type in form input field, but its not working. Currently its in readonly mode, I am not sure why . Here is the component :
import React from 'react';
export default class SearchBar extends React.Component {
constructor(props) {
super(props);
this.state = { term: ''};
this.onInputChange = this.onInputChange.bind(this);
}
onInputChange(event) {
console.log(event.target.value);
this.setState({ term: event.target.value});
}
render() {
return (
<form className="input-group">
<input
placeholder="Give a five day forecast"
className="form-control"
value={this.state.term}
onChange={this.noInputChange}
/>
<span className="input-group-btn">
<button type="submit" className="btn btn-secondary"> Submit</button>
</span>
</form>
)
}
}
onChange={this.noInputChange}
should be
onChange={this.onInputChange}