I'm currently working on a search bar and the value of the input is not displaying in the search bar. When I log the value in the console it only displays one character at a time
I'm assuming that the way that I have set up my state and term is incorrect and rewriting the state everytime it fires, rather than updating it?
Cheers
You have an extra = sign in your setState function.
this.setState is a function, not a variable. You have to pass argument into it, not assign a new value.
Change it into:
this.setState({ term: event.target.value })
Related
i have an object stored in localStorage lets say myObject, when ever i get this object then update a key inside of it then try to use localStorage.setItem to update it, it updated all the keys inside that object.
the object keys are unique since they are reflecting other object IDs.
example code:
let obj = localStorage.getItem('myObject') || '{}'
obj = JSON.parse(obj)
obj[this.currentItem.id] = 'some value here'
localStorage.setItem('myObject', JSON.stringify(obj)) // updates all keys inside the object to be the same value
ok i think i knew where the problem for this was but i don't know why it was happening, i am using Vue for my app and in the mounted function i was getting the item details using the id passed in the route, when i tried to console.log(this.item) it was fine until i redirected to another item then it started to log all the items i have already been through in this page before, i have no idea why this is happening, this triggered the localStorage.setItem multiple times with different IDs but the same value i had which ended up updating all the keys in object inside the localStorage as well.
i ended up using the id from the route this.$route.params.id instead and that solved it but i still have no idea why the mounted was triggering multiple times like this and why it was triggering with different object everytime :/
if this is something in Vue about rendering and lifecycle and someone knows why, could you please link some articles so i can read about it, i am still starting in Vue.
In the child component, I change the checkbox state and want to pass the value of this state to the parent component. Transfer this value to the parental state. Now my code looks like this. In Teaser component, autocomplete is undefined and the code does not work
enter image description here
setSwitchValue don't return any value. so nothing is passed back to callback and like #DanneManne mentioned you have one typo mistake.
The callback chain looks right, but it also looks like you are using the wrong variable in Teaser on line 13. I assume it should check the value of autocompleteData and not autoComplete (which is a function).
I call an API, get a payload and load it into state. Eg:
Payload : {
id: 1,
firstName: 'Craig',
surname: 'Smith',
anotherField: 'test data',
....
}
(Note, there are around 20 fields in real life)
On my react screen, I have the fields to display this data. At the moment, for every field, I have an onChange function. So:
this.firstnameOnChange = this.firstnameOnChange.bind(this);
and then the function:
firstnameOnChange() { ....}
Is there a simpler pattern to maybe lessen the amount of methods I need to create? Some sort of generic OnChange event that takes a name, and the value, which can then be used to update the state?
I can bind to something like:
myOnChange(fieldName, value) {
// Somehow find the 'fieldName' in the state and update it's value with 'value'
}
Is this a valid pattern? Or is there a better way? Or should I stick to separate OnChange methods for each field?
If I can go generic, how would I find the name of the field in the state to update?
No this is not recommended to write onChange for every field. You can write a generic onChange method like this:
handleChange= name => event => {
this.setState({payload: {...this.state.payload, [name] : event.target.value}});
}
for example you have an input like this :
<Input onChange={this.handleChange('firstName')} placeholder="Please Enter" />
PS here we are invoking handleChange directly so we use currying means a new instance being created for every invocation. There is another approach by extract name form event.target and create a name attribute in your input. Then you don't need to pass input name explicitly.
Since the state is an object that means you can update it's key and value.
All you have to do is pass down the correct parameters to a generic update function which will update the state.
Here's one way you can do it:
https://codesandbox.io/s/v382v6l483
Since your payload is an entry one level down, we'll be using the spread operator and spread out the payload object.
Update the value that you need and finally returns the payload to setState function to update the state and rerender the component.
You can bind this function to each field and keep your state updated.
Read more here on handling events and binding functions: https://reactjs.org/docs/handling-events.html
In my React component, I have a function which calls this.setState, and updates a few states. However, one of them is always one state "behind", and I suspect it's because of how it's called.
Here is the function in which the states are set:
handleReps(reps) {
var average = this.getAverage();
this.setState({
var1: CALCULATORS.epley(reps, this.state.weight),
var2: CALCULATORS.brzycki(reps, this.state.weight),
var3: CALCULATORS.lander(reps, this.state.weight),
// some more
average: average
});
}
Now, all of these update fine, and are changed in the DOM, but the average state is always one cycle behind. That is to say, it always shows the value that it should have had BEFORE the last change. I.e. the last time setState was called.
Are there some known factors that might be causing this delay on one of the states?
EDIT: Here is the getAverage() function.
getAverage () {
return CALCULATORS.average([
this.state.epley, this.state.brzycki, this.state.lander,
this.state.lombardi, this.state.mayhew, this.state.oconner,
this.state.wathen
])
}
The problem here was two-fold.
As Igorsvee accurately pointed out, I was calculating the average using old states. Rookie mistake on my part.
The problem however, persisted after I started using "new" states. At that point, I learned that the states aren't mutating immediately, so even if I had the correct order, it was still using one-cycle-old states.
This was solved by passing a callback as a second argument to the setState function. This callback is called AFTER mutation, and will use brand new values.
You use the current values from state to calculate the average, but at the same time you update the state with the new values.So,basically, you store the stale data for the average.I'd suggest to not store the calculated data, but rather invoke the method to calculate it, once you need it.
I've been using $watchGroup to watch a range of fields and trigger a range of functions depending if a particular field has been changed.
I've set up the following plnkr to demonstrate the unexpected behaviour I've came across.
$scope.$watchGroup(['first', 'second', 'third'], function(newValues, oldValues)
{
var message =
{
first: newValues[0],
second: newValues[1],
third: newValues[2],
firstOld: oldValues[0],
secondOld: oldValues[1],
thirdOld: oldValues[2]
};
if(newValues[0] !== oldValues[0]){
console.log('First changed')
}
if(newValues[1] !== oldValues[1]){
console.log('Second changed')
}
if(newValues[2] !== oldValues[2]){
console.log('Third changed')
}
$scope.messages.push(message);
});
The scenario involves three watched fields and I'd like to trigger a function depending on which field has changed. I've been using the 'newValues' and 'oldValues' to monitor which field has changed.
The problem I've came across is that if I've changed the "Second" field then go and change the "First" or "Third" field, the "Second" function is triggered as its storing the previous 'newValues' and 'oldValues' which makes it look like the "Second" field has changed as demonstrated in this image.
I've highlighted the anomaly in the picture. I'd expect once I started changing the "Third" field, the 'newValues' and 'oldValues' for "Second" to be the same as it isn't the field changing.
I'm aware that I could persist two levels of old values and compare them to get around this however I'd expect it to work as I've described. Any clarification if this is a bug or intended functionality would be appreciated.
The angular documentation for $watchGroup states that watchExpressions is an "Array of expressions that will be individually watched using $watch()". Which makes me think that this isn't intended functionality.
Going by the Angular docs for $watch group and that it internally uses $watch for each individual expression I think what you are seeing is the expected behavior
From the docs for $watchGroup,
* The `newValues` array contains the current values of the `watchExpressions`, with the indexes matching
* those of `watchExpression`
* and the `oldValues` array contains the previous values of the `watchExpressions`, with the indexes matching
* those of `watchExpression`
So the new value always has only the latest value and old values contains the previous value.
Secondly, the $watchGroup internally calls the $watch [And what you see is the same behavior for watch]. $watch updates the last value and current value and then calls the listener function only if the current value is different from last value. So in this case, say when you update 'first' expression after 'second' expression, the listener function is not invoked for the 'second' expression and old value is still 'second value'.
If your listener function is really dependent on the which expression has changed, then you are better off using $watch instead of $watchGroup [IMHO, i don't see a performance difference as the $watch is going to be triggered for all expressions]. But if you want call a common handler and pass all new values irrespective of which expression has changed then you could go for $watchGroup.
All said, it would be still be good if you could post this in angular group and get it confirmed from "horse's mouth" :)