update variable inside componentDidUpdate fails - react-native

I'm having a popup in my view and inside the popup there's a countdown timer. I need to hide the popup when countdown timer has value1 . This is what I tried.
componentDidUpdate() {
if (this.state.count === 1) {
clearInterval(this.intervalDuration);
this.setState({popupvisible:false})
}
}
I'm getting an error when the count equals to 1 as follows.
Maximum update depth exceeded. This can happen when a component repeatedly calls setState inside componentWillUpdate or componentDidUpdate. React limits the number of nested updates to prevent infinite loops.

You have to add condition in componentDidUpdate,
The componentDidUpdate is particularly useful when an operation needs to happen after the DOM is updated
componentDidUpdate(prevProps) {
if (prevProps.data !== this.props.data) {
if (this.state.count === 1) {
clearInterval(this.intervalDuration);
this.setState({popupvisible:false})
}
}
}
You can learn more about componentDidUpdate on official document :
https://reactjs.org/docs/react-component.html#componentdidupdate

If you are setting a state variable, then that variable can also be added in condition to avoid recurring update.
componentDidUpdate() {
if (this.state.count === 1) {
clearInterval(this.intervalDuration);
if(this.state.popupvisible){
this.setState({popupvisible:false})}
}
}

This is happening because when count reaches the value 1 yourcomponentDidUpdate sets the state and since there is no check to control when to update your state based on popupVisible's value, your componentDidUpdate is called again and again causing an infinite loop. What you'd what to do is have a check if popupVisible is true, then only set it to false.
componentDidUpdate() {
if (this.state.count === 1) {
clearInterval(this.intervalDuration);
if(this.state.popupvisible) {
this.setState({ popupvisible:false });
}
}
}

Related

count child components programmatically

In a Vue app there is a page being developed that has multiple child components. Each child emits an event to the parent. Here is a code snippet of a few components in the template:
<warehouses-01 #component-loaded="() => this.componentsLoaded.push('warehouses-01')" />
<warehouses-03 #component-loaded="() => this.componentsLoaded.push('warehouses-03')" />
<warehouses-04 #component-loaded="() => this.componentsLoaded.push('warehouses-04')" />
<warehouses-07 #component-loaded="() => this.componentsLoaded.push('warehouses-07')" />
Related code in the script tags -
export default {
watch: {
componentsLoaded() {
if (this.componentsLoaded.length === 4) this.isLoaded = true;
}
},
data() {
return {
componentsLoaded: [],
isLoaded: false
}
}
}
When the isLoaded property becomes true then other code (not shown above) takes action. The issue is that when new child components get added the hard coded value within the watcher needs to be updated manually. I have forgotten this manual update step multiple times and then wonder why the page isn't behaving as expected. To eliminate this step - is there a way to programmatically count the number of child components or, better yet, count the number of child components that emit the "component-loaded" event?
This could be a solution:
watch: {
componentsLoaded() {
let componentCounter = this.$children.filter( i => i.$listeners['component-loaded'] ).length;
if (this.componentsLoaded.length === componentCounter) this.isLoaded = true;
}
},

Vue watch triggered when there is no (discernible) change to object

I have an object that I am watching in vue for the purpose of performing an action whenever a change is detected in it. Something keeps triggering it, but when I print the object to the console and compare the oldVal to newVal they seem identical.
Just looking at the objects logged to the console revealed no differences to my eye, so I thought that by stringifying them and comparing them in a text compare tool I would find differences, but there too the results were identical for code like this:
watch: {
CCompPrefs: function (newVal, oldVal) {
console.log('CC changed: ', JSON.stringify(newVal), ' | was: ', JSON.stringify(oldVal))
}
},
While not understanding why the watch was being triggered if nothing in the object had changed, I thought it was safe to do something like this:
watch: {
CCompPrefs: function (newVal, oldVal) {
if (newVal !== oldVal) {
console.log('CC CHANGED, OLD VAL DIFFERENT')
}
}
},
But the log ran, despite there being no discernible difference I could find!
So I found a working solution by doing this:
watch: {
CCompPrefs: function (newVal, oldVal) {
if (JSON.stringify(newVal) !== JSON.stringify(oldVal)) {
console.log('CC CHANGED, OLD VAL DIFFERENT')
}
}
},
But this still leaves me the nagging question of WHY this is being triggered in the first place. What could possibly be changing and why?
Supplementary info
CCompPrefs is coming via a computed element in the following way:
computed: {
CCompPrefs () {
return this.$store.state[this.$attrs.useCase].filter(x => (x.show === true && x.enabled === true))
},
}
Almost any action will seemingly trigger this watch. Like throwing up a model window.
Using Vue devtools, I can verify that there are NO mutations being applied to ANY part of the vuex store
UPDATE
Now I am wondering if this.$attrs.useCase in my computed value above might be the culprit. The modal I am opening is in a parent container, perhaps that switches the context for that value and forces an update? Looking into it now...
UPDATE2
Nope. this.$attrs.useCase does NOT change. So still confused, WHAT could be triggering this watcher?
I avoided redundant calls for unchanged data by crudely checking the object matches in my handler like this:
data: () => ({
lastDataString: '',
}),
itinerary: {
handler: function(v) {
// Avoid redundant calls
let dataString = JSON.stringify(v)
if (dataString === this.lastDataString){
return
}
this.lastDataString = dataString
// do stuff
},
deep: true,
},

Watch two variables and only trigger if both have been changed ? VueJs

I want to watch two variables (or more) and trigger a method only if both variables change. So far, I have only figured out how to watch multiple elements and trigger a function when one element changes.
is there any solution ?
You can try the following:
computed: {
twoVariables: {
return [this.var1, this.var2]
}
},
watch: {
twoVariables(newValue, oldValue) {
if (newValue[0] !== oldValue[0] && newValue[1] !== oldValue[1]) {
//do stuff
}
}
}

My State value is not Changing ,when button is pressed

onButtonPress = () => {
min = 1000;
max = 9999;
randomotp = min + (Math.random() * (max - min));
console.log(Math.round(randomotp));
this.setState({
otpfield:'#48A23A'
});
console.log('result',this.state.otpfield);
}
}
I have been executing this function in the Button on click , but the corresponding (i,e Otpfield) value is not changing
React does not update the state immediately, it's an asynchronous operation. Therefore your console.log() call is invoked too fast and the state is not yet changed.
Use the "afterUpdated" callback instead (second parameter of the setState method):
this.setState(
{property: true},
() => console.log(this.state.property)
);
The state will not change. onButtonPress function must finish executing first before changing the state.
use componentDidUpdate lifecycle method to check if the state changed
componentDidUpdate(prevProps, prevState) {
console.log('result',this.state.otpfield);
//new State
console.log('result',prevState.otpfield);
// prev State
}

Error in callback for watcher “get_settings”: “TypeError: Cannot read property ‘general’ of undefined”

Please help me out, how to handle this error i cant seem to handle this out as i am new to vue.
what im doing is getting data from server in store vuex with action. Now in component im accessing that data with getter in computed property and trying to watch that property but on component mount i get that error in console but functionality works fine.
data: function() {
return {
settings_flags :{
general: 0,
privacy: 0,
layouts: 0,
message: 0
}
}
}
1: mounting
mounted() {
let self = this;
self.userid = this.getUserId();
this.$store.dispatch('getGallerySettings',self.req);
self.initial_settings();
}
2: computed
computed: {
get_settings() {
return this.$store.getters.getGallerySettings;
}
}
3: watch
watch: {
'get_settings': {
deep: true,
handler() {
let self =this;
if (this.$_.isMatch(self.get_settings.gallery_settings.general,self.initialSettings.gallery_settings.general) == false) {
self.settings_flags.general = 1;
} else {
self.settings_flags.general = 0;
}
}
}
}
It seems to me that your watcher is looking for a property 'general' that is a child of gallery_settings.
get_settings.gallery_settings.general
In the meantime in data you have a property general that is a child of 'settings_flags'. Those two don't line up. So make sure that either your watcher is looking for something that exists when the component starts up, or tell your watcher to only start watching ' get_settings.gallery_settings.general' when 'get_settings.gallery_settings' actually exists.
if (get_settings.gallery_settings) { do something } #pseudocode
I'm not sure that's your problem, but it might be.