React event handling between Child and Parent Component - reactjs

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!

Related

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

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} />

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>
);
}

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>
);
}
}

React access Dom Nodes from this.props.children

Let's say I have a Card that contains a login Form
<Card>
<LoginForm/>
</Card>
How do I access the nodes from the Form within the Card render function?
<Form >
<input type="text" name="email"/>
<input type="password" name="password"/>
<input type="submit"/>
</Form>
Because what i´d like to do is to render the submitbutton not within the props.children context but render it wrapped outside of the given child!
render () {
return (
<div className="card">
<div className="inner">
{/* render Children */}
{this.props.children != undefined ?
<div className="childrenWrapper">
{this.props.children}
</div>
: ""
}
</div>
{/* render submit from login form here, not above */
</div>)
There are some components which actually do what I want. For example the Tabs component from react-toolbox. They somehow manage to render what's within the Tab (children) somewhere else
Just for instance
<Tabs index={this.state.inverseIndex} onChange={this.handleInverseTabChange} inverse>
<Tab label='First'><small>First Content</small></Tab>
<Tab label='Second'><small>Second Content</small></Tab>
<Tab label='Third'><small>Third Content</small></Tab>
<Tab label='Disabled' disabled><small>Disabled Content</small></Tab>
</Tabs>
Which will lead to the following html
As you can see the children from the tab where rendered within their own section
I do not want to change anything on the Form to solve this problem, I would like to pass the Form into the Card and let the Card decide how the Form will be rendered within the card render function.
Since I'm trying to implement the Google Material Design Card component and just use it as a template there are more elements coming which will need to be split up and placed at the positions I want them to be. The thing is I could actually place the relevant HTML around the Form to get it as the Card I want it to be, but then I wouldn't need the component at all.
There are some decent answers here, but none of them directly answer your question. Therefore, even though you should refactor your code (as elucidated below), I am going to provide you a working solution:
class Card extends React.Component {
constructor() {
super();
this.state = {};
}
render() {
console.log(typeof this.props.children)
return (
<div>
{typeof this.props.children === 'object'
? React.cloneElement(this.props.children, { ref: (n) => this.form = n })
: null}
<button onClick={(e) => console.log(this.form.data)}>submit</button>
</div>
);
}
}
class Form extends React.Component {
constructor() {
super();
this.onChange = this.onChange.bind(this);
this.state = {};
}
onChange(e) {
this.data = e.target.value;
}
render() {
return (
<form>
<input type="text" onChange={this.onChange} />
</form>
);
}
}
ReactDOM.render(
<Card><Form /></Card>,
document.getElementById('container')
);
https://jsbin.com/fohehogozo/edit?js,console,output
By setting a property on the instance, you can then access that property from children by using a ref. I checked for typeof === object here, because there was only one child.
WARNING: this code is NOT PRODUCTION READY. Do not ever run this in production. The code I have demonstrated is a terrible hack, and you should never try this at home.
If you are trying to submit a form, maybe look at passing down an onChange event and storing the value (based on the name of the field) in the state of the Card. Then attach the onChange event on the inputs so as soon as they're updated, the data will be passed back up to the container for you to submit.
If you would like to split up the childrens passed, you can simply filter the children array to split up the children, however your childrens seem to be nested.
Why dont you let the cards children handle the separation between your inner container and other content?
I think restructuring in this case is more suitable than modifying the passed children property.
Also, pulling the submit button out of the actual form tags, would break your form as it would no longer submit without some custom connection between the button and the actual form.
Don't try to manipulate the DOM; it's generally an anti-pattern in React (though there are a few valid use cases). In your case, rather than literally trying to move the elements, I'd simply hide the button in the form and add it to the parent.
Assuming you have access to the internals of <LoginForm>, you can add a prop to hide the button:
const button =
<div class="flatbuttonWrapper">
<input type="submit"/>
</div>;
<Form>
<input type="text" name="email"/>
<input type="password" name="password"/>
{!this.props.hideButton && button}
</Form>
Add the button to the Card component:
render() {
return (
<div className="card">
<div className="inner">
{this.props.children != undefined ?
<div className="childrenWrapper">
{this.props.children}
</div>
: ""
}
</div>
<div class="flatbuttonWrapper">
<input type="submit"/>
</div>
</div>
);
}
Finally, in your parent:
<Card>
<LoginForm hideButton />
</Card>
All that said, it really feels like you need to structure your code better and break some of these components up into smaller, more reusable pieces. For example, the Card component probably shouldn't be affecting the button's style or conditionally rendering children; it should just add a frame around any children. Then you can create a more complex component that composes these simpler sub-components to to whatever you need.

React : Is this possible to replace a "placeholder template tag" send as children?

I have for example this code below :
<AjaxForm>
<input type="hidden" name="xxx" value="xxx" />
<div className="grid">
<div className="gdcol-xs-11">
[[SUBMIT_BUTTON]]
</div>
<div className="gdcol-xs-11">
[[CANCEL_BUTTON]]
</div>
</div>
</AjaxForm>
And I would like, for example, be able in the AjaxForm component to replace the tag placeholder 'SUBMIT_BUTTON' by this :
<a href="javascript:void(0);" onClick={this.handleSubmit}>VALIDATE</a>
Is there a way to do this by iterating on this.props.children in the AjaxForm component ?
Is this possible to find some text pattern by crawling all the children ?
Should I have to use refs or a key ?
Thank you in advance !
---- EDIT
To add some informations, this is the render of the AjaxForm Component
return (
<form action="" method="post" ref={this.ajaxRef} id={this.props.id} onSubmit={this.onSubmit}>
<input type="hidden" name="form_id" value={this.props.id} />
{this.props.children}
<input type="submit" value="" className="fake-submit" />
<div id={("ajax-") + this.props.id + ("-messages-container")} className="ajax-form-messages"></div>
</form>
)
I think I understand your issue now. You're generating a component inside AjaxForm and you want to be able to place that component dynamically. In that case you should create another component called AjaxFormContents (or whatever your specific form should be called) which receives your generated component via props and places it wherever you want.
// AjaxForm.js
...
render() {
return React.cloneElement(this.props.children, {
submitButton: this.generateSubmitButton() // or however you're doing it
})
}
...
Now whatever component you put as a child will have access to this component.
// AjaxFormContents.js
...
render() {
return ( // arrange your form contents however you like!
<div>
<input />
{ this.props.submitButton }
</div>
)
}
Then in your parent component:
// Parent.js
...
render() {
return (
<AjaxForm>
<AjaxFormContents />
</AjaxForm>
)
}
This should work, however another approach -- using a higher order component (HOC) would be a nice solution here as well, because your AjaxForm doesn't display anything, it just wraps your form contents.. instead AjaxForm can be an HOC which passes a generated submit button component to the wrapped component.
var ajaxForm = function (WrappedComponent) {
return React.createClass({
generateSubmitButton() {
return <a>your special submit button </a>
},
render() {
<WrappedComponent submitButton={ this.generateSubmitButton() } />
}
})
}
Then you can have the exact same AjaxFormContents component as above and when you export it:
// or module.exports, whichever one you're using.
export default ajaxForm(AjaxFormContents)

Resources