Value not updating inside a ReactJS function - reactjs

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

Related

React Send child input data to update parent state

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

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!

React Checkbox Depends on Parent State

In my parent component, I have a regular component that renders checked based off state and it can call a function:
<input
name='shiftOne'
type='checkbox'
onChange={() => this.onCheck('shiftOne')}
checked={this.state.shiftBools['shiftOne']}
/>
This works fine except for a warning in the console saying that I am switching from controlling and uncontrolling, but it doesn't break anything.
Trying to do the React way, I seperate this Checkbox out into it's function:
function Checkbox (props) {
return (
<div>
<label>
<input
type='checkbox'
name={props.name}
checked={props.checked}
onChange={() => props.handleCheckChange(props.name)}
/>
{props.text}
</label>
</div>
)
}
export default Checkbox
And then I render it in my Root App Component:
<Checkbox
checked={this.state.shiftBools.shiftOne}
name={'shiftOne'}
onChange={() => this.handleCheckChange('shiftOne')}
text={shiftOne[0] + ' ' + shiftTwo[1]}
/>
When I use the Checkbox functional component, it's on change doesn't work, it just always stays checked. Also, it doesn't even call the function in the onChange. I tried to console.log inside it and it's not called:
handleCheckChange = () => {
console.log(1)
this.setState({
shiftBools: {
...this.state.shiftBools,
shiftOne: this.state.shiftOne
}
})
}
I am trying to think more in React and just using the input in the parent class works fine, I'm just not sure why the functional component isn't working. All the data is in my parent state and whether the checkbox is checked or not depends on the data I have in that state.
* EDIT *
I changed the functional component to a Class component:
class Checkbox extends Component {
constructor(props) {
super(props);
this.handler = this.handler.bind(this);
}
handler() {
this.props.onCheck(this.props.name);
}
render() {
return (
<label>
<input
type="checkbox"
name={this.props.name}
checked={this.props.checked}
onChange={this.handler}
/>
{this.props.text}
</label>
);
}
}
Now I deal with the parent function through a handler function. I also binded the parent function, as I wasn't before:
this.onCheck = this.onCheck.bind(this);
Now my checkbox is rendered in the parent function like so:
<Checkbox
name={"shiftOne"}
checked={this.state.shiftBools.shiftOne}
onCheck={this.onCheck}
/>
This post helped me: How do I define methods in stateless components?
although my question was a little vague. Thanks for all your help.
You need to change the way you are calling onChange handler
Change
onChange={() => props.handleCheckChange(props.name)}
To
onChange={props.handleCheckChange(props.name)}
also, change the way of passing handler down has props to Checkbox component
<Checkbox
checked={this.state.shiftBools.shiftOne}
name={'shiftOne'}
onChange={this.handleCheckChange('shiftOne')}
text={shiftOne[0] + ' ' + shiftTwo[1]}
/>

React form input won't let me change value

I have a component in a React class in my Laravel project which is a simple form with one input field. It houses a phone number which I have retrieved from the database and passed back through the reducer and into the component as a prop. Using this, I have passed it through to the module as a prop which then populates the field with the currently saved value:
<OutOfOfficeContactNumberForm
show={props.showOutOfOffice}
value={props.outOfOfficeNumber}
handleChange={console.log("changed")}
/>
I have a handleChange on here which is supposed to fire a console log, but it only ever displays on page load. Here is my form module class:
class OutOfOfficeContactNumberForm extends React.Component {
render() {
const { show, value, handleChange } = this.props;
if(!show) return null;
return (
<div>
<p>
Please supply an Out of Office contact number to continue.
</p>
<InputGroup layout="inline">
<Label layout="inline" required={true}>Out of Office Contact Number</Label>
<Input onChange={handleChange} value={value} layout="inline" id="out-of-office-number" name="out_of_office_contact_number" />
</InputGroup>
</div>
);
}
}
export default (CSSModules(OutOfOfficeContactNumberForm, style));
The form is embedded in my parent component, as follows:
return (
<SectionCategoriesSettingsForm
isSubmitting={this.state.isSubmitting}
page={this.props.page}
show={this.props.show}
categories={this.props.categories}
submitSectionCategoriesSettings={this._submit.bind(this, 'add')}
updateSelectedCategories={this._updateSelectedCategories.bind(this)}
selectedCategoryIds={this.state.selectedCategoryIds}
storedUserCategories={this.props.selectedCategories}
outOfOfficeNumber={this.state.outOfOfficeNumber}
onUpdateContactNumber={this._updateContactNumber.bind(this)}
/>
);
In my componentWillReceiveProps() function, I set the state as follows:
if (nextProps.selectedCategories && nextProps.selectedCategories.length > 0) {
this.setState({
outOfOfficeNumber: nextProps.outOfOfficeNumber,
selectedCategoryIds: nextProps.selectedCategories.map(c => c.id)
});
}
I'm pretty sure the reason it's not changing is because it's pre-loaded from the state which doesn't change - but if I cannot edit the field how can I get it to register a change?
EDIT: Just to clarify there are also checkboxes in this form for the user to change their preferences, and the data retrieved for them is set the same way but I am able to check and uncheck those no problem
Changes:
1- onChange expect a function and you are assigning a value that's why, put the console statement inside a function and pass that function toOutOfOfficeContactNumberForm component , like this:
handleChange={() => console.log("changed")}
2- You are using controlled component (using the value property), so you need to update the value inside onChange function otherwise it will not allow you to change means input values will not be not reflect in ui.
Check example:
class App extends React.Component {
state = {
input1: '',
input2: '',
}
onChange = (e) => this.setState({ input2: e.target.value })
render() {
return(
<div>
Without updating value inside onChange
<input value={this.state.input1} onChange={console.log('value')} />
<br />
Updating value in onChange
<input value={this.state.input2} onChange={this.onChange} />
</div>
)
}
}
ReactDOM.render(<App />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id='app' />
I think the best way is when you get data from database put it to state and pass the state to input and remember if you want to see input changes in typing, use a function to handle the change and that function should change state value.
class payloadcontainer extends Component {
constructor(props) {
super(props)
this.state = {
number:1
}
}
render() {
return (
<div>
<input value={this.state.number} onChange={(e)=>this.setState({number:e.target.value})}></input>
<button onClick={()=>this.props.buyCake(this.state.number)}><h3>buy {this.state.number} cake </h3></button>
</div>
)
}
}

React refs not giving the correct output for input field

React ref not giving the correct output. It returns 'refr < input type="text" placeholder="ssssssssss" >​' instead of ref objects that contain functions like focus etc.
Please check the below code -
render() {
return (
<div>
<input
type="text"
ref={(refr) => console.log('refr', refr)}
placeholder='ssssssssss'/>
</div>
)
}
So in the console, it prints log as 'refr < input type=​"text" placeholder=​"ssssssssss" >​'. Is there any issue with this?
The ref attribute return a reference to the element or component the ref is on.
try this code :
render() {
return (
<div>
<input
type="text"
ref={function(param) {console.log(param)}}
placeholder='ssssssssss'/>
</div>
)
}
for more detail read this article https://www.reactenlightenment.com/basic-react-components/6.9.html
Here's an example of using refs for the input element
class CustomTextInput extends React.Component {
constructor(props) {
super(props);
this.focusTextInput = this.focusTextInput.bind(this);
}
focusTextInput() {
// Explicitly focus the text input using the raw DOM API
this.textInput.focus();
}
render() {
// Use the `ref` callback to store a reference to the text input DOM
// element in an instance field (for example, this.textInput).
return (
<div>
<input
type="text"
ref={(input) => { this.textInput = input; }} />
<input
type="button"
value="Focus the text input"
onClick={this.focusTextInput}
/>
</div>
);
}
}
Reference link

Resources