Reputation: 33
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>
)
}
}
Upvotes: 3
Views: 3288
Reputation: 2021
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>
);
}
}
Upvotes: 1
Reputation: 7492
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': ''
}
}
Upvotes: 0
Reputation: 1400
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!
Upvotes: 3