import React from 'react';
import { useState } from 'react';
function MyForm() {
[state, setState]=useState("");
return (
<form>
<label>Enter your name:
<input type="text"
value={state}
onChange={(event)=>setState(event.target.value)}
/>
</label>
</form>
)
}
When I do two-way binding in react I don't really understand how it works.
As I know, event.target is a property of an event object that refers to the element that triggered the event. So in this case, if we type something in input field, it will trigger the "onChange" which in turn sets the state to the value of element that triggered this change action (input element) and whilst its value is empty string(because its value attribute is equal to the state). So actually state setter function would have set the state to the current state that makes state and also value attribute always to be the same. But off course, I miss something here. Thanks in advance for any explanation.
If explain it step by step - it gonna be something like this (in the context of your example) :
State is the reactive variable, so then it changes, your component (and nested components) rerenders. On the first render you just set it to default.
Then, this variable is hardly assigned to the value of an input. So in a normal situation you wouldn't be able to change the input at all, BUT.
You set your listener to change the state then this input gets some users interaction. Your type something - your state changes (by that time input is still empty).
As we already know, we changed the state. Component rerenders with new state. For example - we typed letter "T".
This rerender causes new state to assignee to the value of your input, you get value="T".
And boom - you have your new letter.
It can be said that you don't really changing the input - state does.
Hope that explanation was helpful! ;)
I have a structure(nested object) that exists in the attached image and if I want to change the value of info[1] and assign it to info state into the related reducer, but it doesn't update immediately and I think a deep comparison between the previous state and current value didn't occur.
Someone suggested the immutable js but I don't how to use it.
honestly, I've converted assigning a value(the assigned value to info state after triggering action) to List imported from immutable js because of changing the reference address of the prev state and new value but I didn't get the result.
I prepared a sandbox for it:
enter link description here
I expect when I select the cells then push the increase button, selected cells increase one unit increase immediately but it doesn't happen and you must refresh the window to see the changes.
I have a custom form control that implements ControlValueAccessor. I initialize the reactive form group and control with a value. I want to mutate that value internally inside the control component and have the outer form get that mutated value.
This works fine to emit the onChange() event when I interact with the control and a new value is set through the UI, however that initial value (set through FormBuilder) does not trigger a form.valueChanges event when it internally changes, so the form never has the modified value if you never change the value of the control through the UI.
The only way I've figured out how to ensure that the form sees the mutated value is to wrap a setTimeout around the this.onChange(this.value) call, which seems wrong. Trying figure out if anyone has tried this and found a better solution than setTimeout?
Here's a very stripped down stackblitz to show the scenario: https://stackblitz.com/edit/angular-t28bst?file=src%2Fapp%2Fform-control%2Fform-control.component.ts
You can see that the value internally is "hello world" whereas the form outside shows only "hello", unless you click the Update Value button inside the control (which just sets value = value) and then the form sees it. Alternatively, you can uncomment the setTimeout around the onChange() call and see that works too.
I have an autocomplete component which has following props:
value (display text),
onChange (fired on every keystroke)
onSelect(fired when user picks something from the list of
suggestions, passes selected object + display text of selected object - the same as value)
state:
- suggestionsList (I've decided it's a state as it's something internal to the component).
On one of the views parent of this component doesn't care about the value after each keystroke. It just cares about the selected item passed by onSelect handler. So in this scenario value & onChange props are not needed. value could become an internal state of the autocomplete component.
But on one of the other views parent would like to also know about each keystrokes. This means the parent would need to hold the value in his state and also pass it as props. onChange props would be also needed to notify parent to change its state.
How to construct the autocomplete component so it handles both scenarios? Which properties should be props and which state?
Any suggestions appreciated.
In the second case, if the parent needs to know about the current value, it doesn't need to hold the variable, so I guess that if you pass the current value (from an internal state variable) as a parameter to the onChange prop function, the parent will notice the change and update accordingly.
Another way to do it is to use the value property and a internal state variable. What I mean is: if the parent wishes to control the value it will have an state entry for it and will be responsible for updating it, in other case the value property must not be provided because it would end as a constant. Your component will use this property as the current value every time its provided, and the parent should use onChange to update the va;ue that it holds.
You can check the source code of the auto complete component in material-ui.
I am looking for a best practice to have a ReactJS component responsible for the form for users to edit a given entity. Very simplified example here. Actual forms would in many cases have several more fields and more GUI functionality.
React.createClass({
getInitialState: function() {
return {
entity: {
property1: null,
property2: null
}
};
},
handleChange: function(e) {
var entity = this.state.entity;
switch(e.target.name) {
case 'property1':
entity.property1 = e.target.value;
break;
case 'property2':
entity.property2 = e.target.value;
break;
}
this.setState({
entity: entity
});
},
render: function() {
return (
<div className="entity-form">
<form onChange={this.handleChange}>
<input type="text" name="property1" value={this.state.entity.property1} />
<br />
<textarea name="property2" value={this.state.entity.property2}></textarea>
<br />
</form>
</div>
);
}
});
The fields of the form is directly editing an entity object, that could then be saved to a RESTful api. I want the component to be updated as the user change the fields, so the GUI could react based on the input during typing (like validations, info etc).
In theory, I could have the whole state object represent the entity that is being edited, so every property of the entity is first level state variables. However, I want to be able to add additional state variables for GUI functions and other things related to what the component is going to do, so I would prefer the entity object to be one state variable like the "entity" state variable above. The object could of course be some more complicated object, like a Backbone model or similar, but in this simplified example, I just use a simple object whit the required properties.
So, in search of the best practice way to make React components for this purpose, I have some questions:
Props or state.
In this case, I have chosen to put the entity object with the content for the form in a state variable instead of prop. This is to be able to update the object during form input without having to call the parent and update the props. As far as my React experience goes, that would be the best practice for a form component like this.
Controlled or uncontrolled inputs.
In the simplified example above, I use controlled inputs. This leads to updating the state and re-rendering the component on every change (like every character entered of a text field). Is this the best practice? The good thing is that the component has full control of what happens, instead of having defaultValue paramters, and on some event (like the user pressing a save button), the component extract the values, update the entity and save it to the server. Is there any reasons (or opinions) on if controlled or uncontrolled inputs should be used in cases like this?
onChange for the form or every input
The example has an onChange on the form tag, and it causes the handleChange method to be called every time any of the fields in the form is changed. However, since the inputs are controlled (have value parameters), React complains that the input fields does not have an onChange property. Does this mean having a common onChange on the form tag is bad practice, and I should remove it and put onChange on every single field instead?
Updating individual properties
In the above example, I use a switch based on what input field is being update (when handleChange is called). I guess I could instead make sure all field names is in sync with the property names of the entity, and I can set properties of the entity object in handleChange based on the name of the field from the event (e.target.name). However, this makes it hard to have individual needs per field, even if most fields just update an entity property directly. I guess an alternativ is a switch with a default block setting based on the name of the input, and case blocks for any field that require other ways of updating (like filtering the value before setting it on the entity). Please comment this if you know some much better way of handeling field updates this way.
Updating the state entity
One big problem of this example, is the way the entity object is updated. Since the entity variable in the handleChange is set to the entity object from current state, this is just a pointer, and updating the entity variable will change the object in state. The React pages say you should never update state directly. One of the reasons is something I have experienced when updating the state this way before calling setState. If having a shouldComponentUpdate method, the prevState contain the new state, since the content of the prevState argument sent to the shouldComponentUpdate is based on what was in the state when setState was called. As far as I know, there is no simple way to clone a object in javascript. So the question is, when having whole objects that I need to update properties of (and not touching the other values in the object) instead of just running setState of a single state variable, what is the best way to do this without causing theese kinds of state mixups?
Anything that is going to change goes in State.
If you're looking at loading an existing entity and editing it, you want controlled inputs, and you want to set the values accordingly. I tend to stay away from defaultValue in most cases (outside of dropdowns)
This ties back in to your previous question. If you specify a value, you are using a controlled input, and you have to provide an onChange handler for any controlled input, otherwise it is set in stone. A benefit of controlled inputs is that users can't edit them, so if you had some properties locked down (maybe for read only, security reasons), when the user attempts to save, even if they edited the HTML directly, React should pull the property's value from the vDOM representation (could be wrong here, but I believe I've tested this before). Anyway, you have to have onChange set directly on controlled inputs. As far as using event delgation (at the form level), this isn't a bad practice at all for a lot of events, this is just a specific scenario (controlled inputs) where you need onChange events specified for each element.
Not entirely sure what the ask on this one is, but I used refs instead of target.name.
So, you're correct in that you should never alter the state directly, and this is a tricky bit from the docs. React is going to alter state directly, it's just going to do it in the implementation through setState. If you alter state outside of this method call, unexpected things will happen and errors will be thrown.
shouldComponentUpdate only does shallow comparisons, but there are a few solutions here.
One is to stringify the objects, this is a quick and dirty object comparison, don't really recommend it, but it works.
A better solution, and one I have used with React + Flux is to implement a propertyChanged bool, and just check that in your shouldComponentUpdate.
Now, this will require you to be aware of setting it when things change, i.e., you changed something deeper in the object graph. Say propertyOne is an object with a property that gets changed in your handleChange method. You would validate the input however you wish, then set propertyChanged = true, and you then need to implement componentDidUpdate. We're making an assumption here, but if the component has updated, you set propertyChanged back to false so you don't have any further triggering of unwanted updates. I hope that makes sense. It's kinda like a one-way notifyPropertyChanged.
I'm providing a quick example of what I would probably do for a more dynamic implementation that allows you to add more properties to your object (only shallow properties in this implementation, obviously you could write a more robust solution). Let me know if you have any further questions or if I didn't answer something.
http://jsfiddle.net/rpv9trhh/
var e = {
prop1: 'test',
prop2: 'wee',
prop3: 'another property',
propFour: 'Oh yeah!'
};
var FormComp = React.createClass({
getInitialState: function(){
return {
entity: this.props.entity
}
},
render: function() {
var ent = this.state.entity;
var that = this;
var inputs = [];
for(var key in ent){
inputs.push(<input
key={key}
style={{display:'block'}}
type="text"
ref={key} onChange={that._propertyChanged.bind(null, key)}
value={ent[key]} />)
}
return <form>
{inputs}
<input
type="button"
onClick={this._saveChanges}
value="Save Changes" />
</form>;
},
_propertyChanged: function(propName) {
var nextProp = this.refs[propName].getDOMNode().value;
var nextEntity = this.state.entity;
nextEntity[propName] = nextProp;
this.setState({
entity: nextEntity
});
},
_saveChanges: function() {
var updatedEntity = this.state.entity;
for(var key in updatedEntity){
alert(updatedEntity[key]);
}
//TODO: Call to service to save the entity, i.e.
ActionCreators.saveEntity(updatedEntity);
}
});
React.renderComponent(<FormComp entity={e} />, document.body);