ReactJS Passing data from child component, to parent, back to different child - reactjs

I'm new to react so please bear with me.
What I want to do:
Essentially pass data from Child Component, to Parent Component, back to another Child Component.
<ParentComponent>
<ChildComponent1>
<ChildComponent2>
</ParentComponent>
Child Component1 has a form.
When form is submitted...
1.) state should be updated with form's content.
2.) state data should pass onto parent component.
3.) Parent Component should pass the data onto ChildComponent2
4.) ChildComponent2 now has access to data from ChildComponent1, and can manipulate said data.
#4 is my goal, but I seem stuck on #2. I think I'm doing everything right logically, but I'm not sure. When I check my parent state after form submission, the state still looks like it is at its initial state ('').
Here is my code.
import styles from './Body.module.css';
import {LeftPortion} from './LeftPortion/LeftPortion.js';
import RightPortion from './RightPortion/RightPortion.js';
class Body extends Component {
constructor(props){
super(props)
this.state={
teamOne: '',
teamTwo: ''
};
this.updateBetInfo = this.updateBetInfo.bind(this);
}
updateBetInfo(firstTeam, secondTeam){
this.setState({teamOne: firstTeam, teamTwo: secondTeam})
}
render(){
return(
<div className={styles.container}>
<LeftPortion updateParent={this.updateBetInfo}/>
<RightPortion/>
</div>
);
}
}
export default Body;
import styles from './LeftPortion.module.css';
export class LeftPortion extends Component{
constructor(props){
super(props)
this.state={
teamOne:'',
teamTwo:''
}
this.onChange= this.onChange.bind(this);
this.onSubmitForm= this.onSubmitForm.bind(this);
}
onChange(event){
this.setState({[event.target.name]: event.target.value})
}
onSubmitForm(teamOne, teamTwo){
var teamOne = this.state.teamOne;
var teamTwo = this.state.teamTwo;
this.props.updateParent(teamOne,teamTwo)
}
render(){
return(
<div className={styles.container}>
<h4>Enter bet info here:</h4>
<h4>-------------------</h4>
<h4>Straight bet</h4>
<div className={styles.teamEntry}>
<form>
<label>
Team 1:
<input type="text" name="teamOne"onChange={this.onChange}/>
</label>
<br/>
<label>
Team 2:
<input type="text" name="teamTwo" onChange={this.onChange}/>
</label>
<br/>
<input type="submit" value="Submit" onClick={this.onSubmitForm}/>
</form>
<br/>
<div className={styles.betType}>
<form>
<label>
Bet:
<select>
<option value='1'>1</option>
<option value='2'>2</option>
<option value='X'>X</option>
</select>
</label>
<input type="submit" value="Submit"/>
</form>
</div>
</div>
</div>
);
}
}
Basically what I'm stuck on is I need the state in to update to the teamOne and teamTwo entered in the form from the child component, when the form is submitted.

It appears you are not assigning any props to the second component you want the state to update? Is your parent component's state update being executed? If so, assign a state value to child component 2, and it should be working fine. Right now, React won't re-render anything as there are no children with props or state impacted by the update.
<RightPortion/>
This component should have a state value to reflect the update in the parent.
<RightPortion teamOne={this.state.teamOne} />

Related

Difference between React controlled component and uncontrolled component

I am new to react and while learning I come across this example of controlled component.
function App() {
let [fName, setFName]=useState('');
return (
<div className="container">
<h1>Hello {fName }</h1>
<input name ='fname' value={fName} onChange={(e)=> setFName(e.target.value)} type="text" placeholder="What's your first name?" />
</div>
);
}
just adding value={fName} makes is controlled . I don't actually understand what does it mean by controlled component and uncontrolled. Can you explain it from beginner prospective.
An uncontrolled component means that you will let the component itself manage the value. It's own internal mechanism will keep track of it.
Now when you add the value property to the input component, you will start to "control" the component yourself. The value you put into that property, will be the value that will be displayed.
You can literally control the value yourself, by just passing it in as is, or by changing the value before passing it in.
Controlled Components
These components have what is called a callback function that is triggered each time we enter something new in the form element.
Triggering the function will typically store or update what we type in the same React component that displays the form element that was used
Most widespread use it with forms
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>
);
}
}
Unontrolled Components
These components such as <input> typically maintain their own state and update it based on user input.
In other words, they will accept what we type and have the responsibility of remembering it, and in order to retrieve the values they remembered, you have to get it when you need it.
The latter usually happens during form submission. They can be classified under uncontrolled components.
class NameForm extends React.Component {
constructor(props) {
super(props);
this.handleSubmit = this.handleSubmit.bind(this);
this.input = React.createRef();
}
handleSubmit(event) {
alert('A name was submitted: ' + this.input.current.value);
event.preventDefault();
}
render() {
return (
<form onSubmit={this.handleSubmit}>
<label>
Name:
<input type="text" ref={this.input} />
</label>
<input type="submit" value="Submit" />
</form>
);
}
}
Here, Reactjs documentation provided explanation.
A Controlled Component is one that takes its current value through props and notifies changes through callbacks like onChange. A parent component "controls" it by handling the callback and managing its own state and passing the new values as props to the controlled component. You could also call this a dumb component/stateless component.
An Uncontrolled Component is one that stores its own state internally, and you query the DOM using a ref to find its current value when you need it. This is a bit more like traditional HTML.
React form components support both controlled and uncontrolled usage:
// Uncontrolled:
<input type="text" defaultValue="hey" ref={inputRef} />
// Controlled:
<input type="text" value={this.state.value} onChange={onHandleChange} />

React event handling between Child and Parent Component

I'm new to React and couldn't find anything on stack overflow for this. I can't call the event handler from the parent component. However If I copy and paste what's inside of ZipSearchField, into the App parent component (and change the props to this) it works as expected. Code below:
If it's not clear, I want to handle the change in the parent component but can't seem to do so. It never gets called and there is no error anywhere.
function ZipSearchField(props) {
return (
<div className="container-search-bar">
<form>
<label>
<input type="text" placeholder="Try 11223..." onChange={props.handleChange}/>
</label>
</form>
</div>
);
}
class App extends Component {
constructor(props) {
super(props);
this.handleChange = this.handleChange.bind(this);
}
handleChange() {
console.log("things changed")
}
render() {
return (
<div className="App">
<div className="App-header">
<h2>Zip Code Search</h2>
</div>
<ZipSearchField onChange={this.handleChange}/>
</div>
);
}
}
Sorry if this is a dumb question, thank you!
Answered in the comments By Sudhakar RS.
Inside of the child component, you don't call the function but you link the onChange hook to the parent's onChange hook.
So child looks like this:
function ZipSearchField(props) {
return (
<div className="container-search-bar">
<form>
<label>
<input type="text" placeholder="Try 11223..." onChange={props.onChange}/>
</label>
</form>
</div>
);
Thank you!

Value not updating inside a ReactJS function

I have a ReactJs function that displays a simple dialogue box, and is intended to update a value for the parent component. The function looks like this:
export function MyDialogue(props: IMyProps) {
var myValue = 0;
return (
<div style={style}>
<label>Enter a number here: </label>
<input type="text" value={myValue} />
<button onClick={() => props.updateFunc(myValue)}>Update</button>
</div>
);
}
I've tried several variations of this; for example, passing in props.myValue, and even changing the function to a class and passing this.state.myValue in. In all but this example, myValue remains as it was in the parent class, and in this version, always 0.
updateFunc simply calls setState on the parent class, and having traced through it, it never gets called with the changed value.
I've seen some documentation that says to essentially handle the onChange event - is this the only way to make this work, or is there a way to implement data binding in React?
Just bind back your input to the parent's state via props.value;
MyDialogue.js
export function MyDialogue(props: IMyProps) {
return (
<div style={style}>
...
<input type="text" value={props.value} />
...
</div>
);
}
Parent.js
....
render(){
const { dialogueValue } = this.state;
return <MyDialuge value={dialogueValue} updateFunc={this.handleUpdate} />
}
You are using uncontrolled input because You are not keeping value of input inside state.
Solution is
With uncontrolled:
export class MyDialogue extends React.Component<IMyProps, {}>{
constructor() {
super();
this.input = React.createRef();
}
return (
<div style={style}>
<label>Enter a number here: </label>
<input type="text" ref={this.input} />
<button onClick={() => props.updateFunc(this.input.current.value)}>Update</button>
</div>
);
}
With controlled:
Maintain myValue state in parent and pass it to child.
and on change on input event call a function of parent which change myValue using setState,
Maintain myValye state inside MyDialogue and onClick pass it to parent.
You need to change this component to a stateful component
then do a two-way binding for your textbox and have it talk to local state and then use that state value to update parent component.
export class MyDialogue extends React.Component<IMyProps, {}>{
constructor() {
super();
this.state = {
myValue: 0
}
}
onChangeHandler = (event:any) =>{
this.setState({myValue:event.target.value});
}
return (
<div style={style}>
<label>Enter a number here: </label>
<input type="text" value={this.state.myValue} onChange={this.onChangeHandler}/>
<button onClick={() => props.updateFunc(this.state.myValue)}>Update</button>
</div>
);
}

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.

Unnecessary DOM update for dynamic React elements

I have a React project that generates some DOM elements "dynamically" within JSX:
<div className='ui form'>
<h2 className="header">{subtype}</h2>
{
subtypes[subtype].fields.map((field) =>
<div className='field' key={field.name}>
<label>{field.label}</label>
<input name={field.name}
value={entity[field.name]}
onChange={onInputChange}/>
</div>
)
}
</div>
For a specific component, the generated input fields don't ever change during the life of the application (only their props change), so it is just a way to generate forms that are actually static.
So it is exactly equivalent to this "static" JSX:
<div className='ui form'>
<h2 className="header">{subtype}</h2>
<div className='field' key='field1'>
<label>Field 1</label>
<input name='field1'
value={entity['field1']}
onChange={onInputChange}/>
</div>
<div className='field' key='field2'>
<label>Field 2</label>
<input name='field2'
value={entity['field2']}
onChange={onInputChange}/>
</div>
</div>
If I used the first code snippet, then the HTML DOM elements get recreated on every change to state / props. If I use the second snippet, then the HTML appears to be unchanged and only the field values are updated (React can detect in the second instance that the virtual DOM elements are still the same, but not in the first instance)
Is there a way for me to create the "dynamic" virtual DOM in the first code example in a way that it can be cached and reused so that React sees it as being the same on each render?
Many thanks
Where is subtypes coming from? From what I understand you are receiving this in the component's props. If that is the case, you need to store this variable in this component's state. Then, you need to update it's state in it's componentWillReceiveProps lifecycle function.
The thing is, your component will only re-render when it's setState function is called. Hence, the components will not re-render when it's props change (after it has already been mounted).
class SimpleCom extends React.Component {
constructor(props) {
super(props);
this.state = {
subtypes: props.subtypes
}
}
componentWillReceiveProps(props) {
this.setState({
subtypes: props.subtypes
});
}
render() {
const subtypes = this.state.subtypes;
return (
<div className='ui form'>
<h2 className="header">{subtype}</h2>
{
subtypes[subtype].fields.map((field) =>
<div className='field' key={field.name}>
<label>{field.label}</label>
<input name={field.name}
value={entity[field.name]}
onChange={onInputChange}/>
</div>
)
}
</div>
);
}
}

Resources