React Send child input data to update parent state - reactjs

Setup: I have set up a two react components in a parent child relationship. The parent has a state that can be changed by press of a button on parent itself.
Expected behaviour: In the child, I have an input field and I want the state to change to the value I send in the input field on the press of the submit button. I have set up the parent and the child as follows:
What I have tried: I going through this answer and this youtube video but I guess I am not smart enough to make sense of it.
This is what my code looks like
Parent:
class App extends Component {
state = {
value:"someValue"
};
changeValue = (value) => {
this.setState({
value
})
}
render() {
return (
<div>
<p>this is the value from state: {this.state.value}</p>
<button onClick={()=>this.changeValue("valueFromParentComponent")}>Press to change value from parent component</button>
<br/><br/>
<Child getChildInputOnSubmit={()=>this.changeValue()} />
</div>
);
}
}
And this is what the child looks like
Child:
class Child extends Component {
state = {
}
sendChildData = (childInputValue) => {
console.group("This is the data from the input of the child component")
console.log("==============")
console.log(childInputValue)
console.log("==============")
}
render() {
return (
<div>
This is the child component
<br /><br />
<form>
<input type="text" placeholder="Some placeholder"></input>
<button onSubmit={this.sendChildData()} type="submit">Send child's input to parent</button>
</form>
</div>);
}
}

The React behaviour encourages to implement an inverse data flow inside a component hierarchy. Meaning that the child components can receive parent methods through props, this methods will work as callbacks, allowing to receive data, trigger behaviours, update his state and more.
I attach a StackBlitz example, showing how this concept would work in your setup https://stackblitz.com/edit/react-jsv5jo
Edit: Here a few extra tips applied on the example:
To work with inputs on React, a common setup consists on listen the onChange event to receive new data and update the component state. Then, this state is used in the value attribute to update the input content on DOM.
Listen the onSubmit event on the form tag instead on submit button, and remember to add some logic to avoid reloading.
Another good practice on React components is initialize your state object inside the Constructor (In case to be working with a Class Component) and write methods to avoid bloat the render one (Be sure to bind the extra methods on your constructor to avoid invocation problems)

Callbacks are used to pass data from Child component to Parent component in React.
We wright function in Parent component that will receive value and pass this function to child component through Props.
class Parent extends Component {
state = {
value: 'someValue'
};
changeValue = value => {
this.setState({
value
});
};
render() {
return (
<div>
<p>this is the value from state: {this.state.value}</p>
<button onClick={() => this.changeValue('valueFromParentComponent')}>
Press to change value from parent component
</button>
<br></br>
<Child getChildInputOnSubmit={this.changeValue} />
</div>
);
}
}
Now in Child component we call Parents function that we passed in props and send value.
class Child extends Component {
constructor(props) {
super(props);
this.state = {
Childvalue: ''
};
}
handleChange = event => {
event.preventDefault();
this.setState({ Childvalue: event.target.value });
};
sendToParent = () => {
//here calling Parents changeValue
this.props.getChildInputOnSubmit(this.state.Childvalue);
};
render() {
return (
<div>
This is the child Component
<br></br>
<form action='#' onSubmit={this.sendToParent}>
<input
type='text'
placeholder='Some placeholder'
value={this.state.Childvalue}
onChange={this.handleChange}
></input>
<button type='submit'>Send child's input to parent</button>
</form>
</div>
);
}
}

Related

How can I get the values of all sibling input checkboxes in a child component?

I have a parent and a child component (Child1) with another child component (Child2). Child2 has checkboxes:
<input name='val1' id='val1' value='val1' type='checkbox' />
<input name='val2' id='val2' value='val2' type='checkbox' />
I want the parent component to be able to get the values of all the checkboxes (probably comma separated). I either want to pass down a handler or have my parent component be able to read all the values
There are a few ways to achieve this, but the simplest would be something like this:
class Child2 extends React.Component {
onChangeCheckbox(event) {
// Update state of child2 to capture current check state of checkbox
// inputs in Child2
this.setState({
[ event.target.name ] : event.target.checked
}, () => {
// Upload the combined/current state of checkbox name/checked pairs
// to Parent via onInputClicked callback prop
this.props.onInputClicked(this.state)
})
}
render() {
return (<React.Fragment>
<input name='val1' id='val1' value='val1' type='checkbox'
onClick={ event => this.onChangeCheckbox(event) } />
<input name='val2' id='val2' value='val2' type='checkbox'
onClick={ event => this.onChangeCheckbox(event) } />
</React.Fragment>)
}
}
class Parent extends React.Component {
render() {
// Render Child2 with checkbox inputs from Parent and pass onInputClicked
// prop as a callback
return (<Child2 onInputClicked={ values => {
console.log('checkbox values in parent', values)
} } />)
}
}
Hope that helps!

Insert data using multiple components in reactjs

I am trying to insert data in database using multiple components in reactjs. In my first component I have a Form like below (there is not Submit button in this component)
render() {
return (
<form>
<input type="text" name="name" placeholder="Name"/>
</form>
);
}
In second component I am calling that component with if else logic.
In third component I have the submit button like below
<Button
positive icon='checkmark'
labelPosition='right'
onClick={this.insertAddress}
content='Save'
/>
My main issue is using state. How can I use state effectively here ? How can I catch the input values of first component in third component to insert in database ?
You create a parent container. The parent container holds the state, all the methods and event handlers. All of those are binding to the parent.
You then pass the methods and parts of the state down to the children. When they children use them, they will be changing the parent. I created a simple sandbox to demonstrate. You don't need to pass the entire state down, just the parts needed by the children.
https://codesandbox.io/s/q335wnjoyj
Use the concept of Container component.
create a container component which will hold the state of all you child components. keep updating all state related to Data in here. and call save functionality from here.
class Parent extends React.Component{
constructor(props){
super(props);
this.state={
name:'',
email:'',
phone:''
}
this.handleFormChanges = this.handleFormChanges.bind(this)
this.handleSubmit = this.handleSubmit.bind(this);
this.reactToSomeChange = this.reactToSomeChange.bind(this)
}
handleFormChanges(ev){
// handle form and set appropriate state
}
handleFormChanges(ev){
// react to change and set state
}
handleSubmit(){
// update your data store db etc.
}
render(){
return(
<MyForm changes={this.handleFormChanges} />
<IfElse changes={this.reactToSomeChange} />
<Button submit={this.handleSubmit} />
)
}
}
// MyFrom component render function
render() {
return (
<form>
<input type="text" name="name" onChanges={this.props.changes} placeholder="Name"/>
</form>
);
// Button component render function
render(){
<button onClick={this.props.submit}>SUBMIT<Button>
}
Child components need not to call apis to save the data. it should be done from a single parent component that shares the same state in the child components.

Get current state of child component through prop passed by Parent - Reactjs

Im learning react and very new to this, I am tinkering with something to understand this more.
I would like to know if it is possible to console.log the state of the CHILD using a prop passed down by the parent.
Example :
Child component ( has its own state)
Parentcomponent ( has its own state)
Child Component
this.state={
animal:'Lion'
}
<button onClick{this.props.giveMeState}>
And that, I would want to console the state ( animal:Lion)
Parent Component
this.state={
name: 'John'
}
giveMeState(){ ? what can go here, or is it not that simple ?
)
}
Codepen of example
Parent component cannot query the state of the child component. At least, that's not the intended design of React.
What I think you're asking is how to coordinate the state of child with parent, and you're on the right track to use a prop to pass the state from child to parent.
Perhaps a complete example that does what you want would look like this:
class Parent extends React.Component {
state = { name: "John" }
handleChildAnimal = animal =>
this.setState({ animal });
handleClick = e =>
console.log(`Child animal: ${this.state.animal}`);
render() {
return (
<div>
<Child onAnimal={this.handleChildAnimal} />
<button onClick={this.handleClick}>Tell me Animal state</button>
</div>
);
}
}
class Child extends React.Component {
state = { animal: "Lion" }
handleClick = e => {
console.log(`Animal: ${this.state.animal}`);
this.props.onAnimal(this.state.animal);
}
render() {
return (
<button onClick={this.handleClick}>{this.state.animal}</button>
);
}
}
Demo on CodePen.io
if you want to pass the state value of the child to the parent,
you can do it like this,
In the child component add another function getState and call the reference function giveMeState through this function
...
constructor(props) {
super(props)
this.state={ animal:'Lion' }
this.getState = this.getState.bind(this)
}
getState(){
this.props.giveMeState(this.state)
}
....
<button onClick={this.getState}>
....
and also redefine the parent function so that it takes a parameter
and the console.log that parameter
Not sure if this is a good pattern though
Here is another answer just for giving another example.
It does not fulfill your question and as told fulfilling your question would not be the best approach. Maybe you should try to think differently while working React and states.
App
class App extends React.Component {
state = {
input: "initial input state",
childState: "right now I don't know child state",
};
handleInputChange = e => this.setState({ input: e.target.value });
handleChildState = ( childState ) => this.setState( { childState } )
render() {
return (
<div style={styles}>
<h4>This is parent component.</h4>
<p>Input state is: {this.state.input} </p>
<p>Child state is: {this.state.childState}</p>
<hr />
<Input
onInputChange={this.handleInputChange}
getState={this.handleChildState}
/>
</div>
);
}
}
Child component as Input
class Input extends React.Component {
state = {
myState: "some state"
};
handleSendState = () => this.props.getState(this.state.myState);
handleState = e => this.setState({ myState: e.target.value });
render() {
return (
<div>
<h4>This is Child coponent</h4>
<button onClick={this.handleSendState}>
Click me to get child state
</button>
<p>This is my state: {this.state.myState}</p>
<p>Write something to change child's state.</p>
<input type="text" onChange={this.handleState} />
<p>
Write something to change parent's input state
</p>
<input type="text" onChange={this.props.onInputChange} />
</div>
);
}
}

Is it okay to call setState on a child component in React?

I have some text. When you click on that element a modal pops up that lets you edit that text. The easiest way to make this work is to call setState on the child to initialise the text.
The other way, although more awkward, is to create an initial text property and make the child set it's text based on this.
Is there anything wrong with directly calling setState on the child or should I use the second method?
Although it is recommended to keep the data of your react application "up" in the react dom (see more here https://reactjs.org/docs/lifting-state-up.html), I don't see anything wrong with the first aproach you mentioned.
If you have to store data that is very specific of a child I don't see anything wrong in keep that information in the child's state.
It seems that your modal doesn't need to have its own state, in which case you should use a stateless React component.
This is one way of passing the data around your app in the React way.
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
initialText: "hello",
}
this.saveChildState = this.saveChildState.bind(this);
}
saveChildState(input) {
console.log(input);
// handle the input returned from child
}
render() {
return (
<div>
<ChildComponent
initialText={this.state.initialText}
save={this.saveChildState}
/>
</div>
);
}
}
function ChildComponent(props) {
return (
<div>
<input id="textInput" type="text" defaultValue={props.initialText}>
</input>
<button onClick={() => props.save(document.getElementById('textInput').value)}>
Save
</button>
</div>
)
}
Maybe I am misinterpreting your question, but I think it would make the most sense to keep the modal text always ready in your state. When you decide to show your modal, the text can just be passed into the modal.
class Test extends Component {
constructor() {
this.state = {
modalText: 'default text',
showModal: false
}
}
//Include some method to change the modal text
showModal() {
this.setState({showModal: true})
}
render(
return (
<div>
<button onClick={() => this.showModal()}>
Show Modal
</button>
{ this.state.showModal ? <Modal text={this.state.modalText}/> : null }
</div>
)
)
}

React: how to notify parent for changes

I'm trying to wrap bootstrap into components with integrated form validation.
short:
Let's say I have
<Form>
<FieldGroup>
<Field rules={'required'}/>
</FieldGroup>
</Form>
Once Field pases validation, how can I notify FieldGroup (parent node) to add a class?
I created a simplified codepen version here
I would like depending on validation status, then change the state of FieldGroup So I can properly change the class name. (add has-warning has-danger etc) and ultimately add class to the Form component.
You need to pass a callback to the child component. I just forked your codepen and added some snippet as below.
http://codepen.io/andretw/pen/xRENee
Here is the main concept,
Make a callback function in "parent" component and pass it to the "child" component
i.e. The child component needs an extra prop to get the callback:
<Form>
<FieldGroup>
<Field rules={'required'} cb={yourCallbackFunc}/>
</FieldGroup>
</Form>
In <FieldGroup /> (parent):
class FieldGroup extends React.Component{
constructor(props){
super(props);
this.state = {
color: 'blue'
}
}
cb (msg) {
console.log('doing things here', msg)
}
render() {
const childrenWithProps = React.Children.map(this.props.children,
child => React.cloneElement(child, {
cb: this.cb
})
)
return (
<div class='fields-group'>
<label> field </label>
{ childrenWithProps }
</div>
);
}
};
In <Field /> (child):
class Field extends React.Component{
constructor(props){
super(props);
this.state = {
empty: true
}
this.validate = this.validate.bind(this);
}
validate(e){
let val = e.target.value;
console.log(!val);
this.setState({empty: !val});
//here to notify parent to add a color style!
// do call back here or you may no need to return.
this.props.cb(val)
return !val;
}
render() {
return (
<div>
<input type='text' onBlur ={(event) => this.validate(event)}/>
{this.state.empty && 'empty'}
</div>
);
}
};
And you can do the things you want in the callback function. (You can also pass a callback from <Form /> to the grandson and get it work, but you need to rethink the design of it is good or not.)

Resources