How to pass Child Component's form value to Parent Component - reactjs

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': ''
}
}

Related

Add data to the page without refreshing it in React

I've posted this question earlier, but probably not quite clearly formulated it. I have a chat. When I add message it goes to database but not updated on page. So I need it to be updated on page after adding a msg.
Parent component Forms
export default class Forms extends Component {
constructor() {
super()
this.state = {
messages: [],
}
this.sendMessage = this.sendMessage.bind(this);
}
componentDidMount(){
client1.getEntries({limit:300, order: 'sys.createdAt',
content_type:'nameTest'}).then(response => {
this.setState({messages: response.items});
}).catch(e => {
console.log(e);
});
}
sendMessage(data) {
client2.getSpace(client2.space)
.then((space) => space.getEnvironment('master'))
.then((environment) => environment.createEntry('nameTest', {
fields: {
chatName: {
'en-US': data.get('chatName')
... some data
}
}))
.then((entry) => entry.publish())
.catch(console.error)
}
render() {
return (
<div className="chat">
<div className="container-xl">
<MessageList messages={this.state.messages}/>
<SendMsg onSendMessage={this.sendMessage}/>
</div>
</div>
);
}
}
the child component SengMsg
export default class SendMsg extends Component {
constructor() {
super()
this.state = {
message:'',
userEmail:'ddd#gmail.com',
chatName:'ggg'
}
this.sendMessage = this.sendMessage.bind(this)
this.handleChange = this.handleChange.bind(this)
}
handleChange(e) {
this.setState({
message: e.target.value,
})
}
sendMessage(e) {
e.preventDefault();
const { onSendMessage } = this.props;
const form = e.target;
const data = new FormData(form);
// if send message handler was passed, invoke with form data
onSendMessage && onSendMessage(data);
this.setState({
message: ''
})
}
render() {
return (
<div className="send-message">
<Form className="send-msg" onSubmit={this.sendMessage}>
<FormGroup>
<Input type="hidden" name="userEmail" value={this.state.userEmail}/>
</FormGroup>
<FormGroup>
<Input type="hidden" name="chatName" value={this.state.chatName}/>
</FormGroup>
<FormGroup>
<Input
type="text"
name="text"
onChange={this.handleChange}
value={this.state.message}
placeholder="Write your message here"
required />
</FormGroup>
<FormGroup>
<Input type="hidden" name="dateCreated" value={moment().format()} onChange={this.handleChange}/>
</FormGroup>
</Form>
</div>
);
}
}

React Redux setState after action is dispatched

This is my EditStudent component in React where I am using Redux for state management. This is my code of the component.
import React, { Component } from 'react'
import {connect} from 'react-redux';
import {getStudentDetail} from '../actions/studentActions';
class EditStudents extends Component {
constructor(props){
super(props);
this.onInputChange = this.onInputChange.bind(this);
this.state = {
name:this.props.student.name,
email:this.props.student.email,
address:this.props.student.address
}
// this.state
}
render() {
return (
<div>
<form>
<p>
<label>Name</label>
<input type="text" name="name"
value={this.state.name}
onChange={this.onInputChange}
/>
</p>
<p>
<label>Email</label>
<input type="text" name="email"
value={this.state.email}
onChange={this.onInputChange}
/>
</p>
<p>
<label>Address</label>
<input type="text" name="address"
value={this.state.address}
onChange={this.onInputChange}
/>
</p>
<button type="submit">Update</button>
</form>
</div>
)
}
onInputChange(e){
var name = e.target.name;
this.setState({[name]:e.target.value});
}
componentDidMount(){
this.props.getStudentDetail(this.props.studentId());
}
}
let mapDispatchToProps = (dispatch,ownProps)=>{
return {
getStudentDetail: (id)=>{
dispatch(getStudentDetail(id));
},
studentId: ()=>{
return ownProps.match.params.id;
}
}
}
const mapStateToProps = (state)=> {
return {
student:state.students.student
}
}
export default connect(mapStateToProps,mapDispatchToProps)(EditStudents);
Here I am having the problem displaying ajax response in text input field. I am setting component in the constructor but when ajax request completes state is not set.
Is it possible to set state after ajax completes?
I solve it by adding componentWillReceiveProps() function on component.
componentWillReceiveProps(nextProps){
this.setState({
name:nextProps.student.name,
email:nextProps.student.email,
address:nextProps.student.address
})
}
Thanks so much, Sakhi Mansoor for the help.
you need to store input value in your state as you're re-rendering your input so changes are not getting reflected.
Do the folowing changes:
constructor(props){
super(props);
this.onInputChange = this.onInputChange.bind(this);
this.state = {
email:this.props.student.email,
address: this.props.student.address
}
}
In you render:
<p>
<label>Email</label>
<input type="text" name="email" value={this.state.email} onChange={this.onInputChange('name)}/>
</p>
<p>
<label>Address</label>
<input type="text" name="address" value={this.state.address} onChange={this.onInputChange('name')}/>
</p>
onInputChange= name => event => {
this.setState({
[name]: event.target.value,
});
};
There are two ways
First -
constructor(props) {
super(props);
this.state = {
firstName: ""
};
}
componentDidMount() {
this.props.userProfile(); // Redux Action
}
componentWillReceiveProps(nextProps) {
console.log(nextProps);
this.setState({
firstName: nextProps.user.firstName
});
}
Second -
constructor(props) {
super(props);
this.props.userProfile(); // Redux Action
this.state = {
firstName: ""
};
}
static getDerivedStateFromProps(props, state) {
return {firstName: this.props.user.firstName };
}

Updating state in parent with Draft editor state?

I have a Draftjs editor in a form with other fields. The state for all those fields is being controlled in that parent component. How do I get the same behavior from the Draft editor as I do from the regular HTML form fields where it updates the parent state?
Regular input:
<input value={title} type="text" onChange={this.handleChange} name="title" placeholder="Title" id="title" />
Draft js editor:
<TextEditor placeholder="Write your summary..." value={summary} toolbar />
On change handler:
handleChange(event) {
this.setState({[`${event.target.name}`]: event.target.value});
};
You can simply Do :
In parent : (not that I have add the update={ this.update } props)
…
render(){
return (
<input value={title} type="text" onChange={this.handleChange} name="title" placeholder="Title" id="title" update={ this.update }/>
);
}
update(editorState){
console.log('update',editorState);
}
…
In editor :
handleChange(event) {
this.setState({[`${event.target.name}`]: event.target.value});
this.props.update(this.state);
};
This will call the update() function of the parent, is that what you are searching for ?
Edit :
import React from 'react';
import ReactDOM from 'react-dom';
import {Editor, EditorState} from 'draft-js';
class Parent extends React.Component {
…
render() {
return (
<div>
<form>
<MyEditor update={ this.update }>
<form>
</div>
);
}
update(editorState) {
console.log('editor s state', editorState);
}
…
}
// from draft website :
class MyEditor extends React.Component {
constructor(props) {
super(props);
this.state = {editorState: EditorState.createEmpty()};
this.onChange = (editorState) => {
this.setState({editorState});
this.props.update(this.state);
}
}
render() {
return (
<Editor editorState={this.state.editorState} onChange={this.onChange} />
);
}
}
ReactDOM.render(
<Parent/>,
document.getElementById('container')
);

Handling multiple onChange callbacks in a React component

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

React: Input field doesn't receive input

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}

Resources