The useFocusEffect doesn't update setstate - react-native

I have this useFocusEffect function:
useFocusEffect(
useCallback(() => {
async function setFilterValue() {
let filterValue = await AsyncStorage.getItem('filterValue');
let inputValue = JSON.parse(filterValue);
if (gpsFilterValue === null) {
setGpsFilterValue(inputValue);
console.log('null')
// setRefreshing(true)
} else if (inputValue !== parseInt(gpsFilterValue)) {
setGpsFilterValue(inputValue);
console.log('refreshing1')
setTimeout(() => {
console.log(gpsFilterValue)
}, 1000);
//console.log(inputValue + ' ' + gpsFilterValue)
//setRefreshing(true)
} else {
console.log('test')
}
}
setFilterValue();
}, [])
);
When I debug the gpsFilterValue in the setTimeout it stays undefined, but when I make a button in the render to debug the gpsFilterValue state value and press it, it has updated. How come the values are different?

From the looks of it gpsFilterValue is part of your state as you have a state setter being invoked in the callback. However, your useCallback isn't listing gpsFilterValue as a dependency (that empty array that is the second parameter to useCallback. Add it to that dependency list and you should see the updated value.
useFocusEffect(
useCallback(() => {
async function setFilterValue() {
let filterValue = await AsyncStorage.getItem('filterValue');
let inputValue = JSON.parse(filterValue);
if (gpsFilterValue === null) {
setGpsFilterValue(inputValue);
console.log('null')
// setRefreshing(true)
} else if (inputValue !== parseInt(gpsFilterValue)) {
setGpsFilterValue(inputValue);
console.log('refreshing1')
setTimeout(() => {
console.log(gpsFilterValue)
}, 1000);
//console.log(inputValue + ' ' + gpsFilterValue)
//setRefreshing(true)
} else {
console.log('test')
}
}
setFilterValue();
}, [gpsFilterValue])
);

Related

swimlane/ngx-datatable, How can I kick the cellClass function?

The cellClass function is not called when the component properties change.
How do I kick a rowClass orcellClass?
#Component({
...,
template: `<ngx-datatable [rowClass]="rowClass"></ngx-datatable>`
})
class SomeComponent {
someVariable = true;
rowClass = (row) => {
return {
'some-class': (() => { return this.someVariable === row.someVariable })()
};
}
}
Related
https://github.com/swimlane/ngx-datatable/issues/774
I was able to solve it by changing this.rows.
https://swimlane.gitbook.io/ngx-datatable/cd
this.rows = [...this.rows];
If you are using a store, you need to cancel the immutable attribute.
Example
#Input() set list(list: Record<string, unknown>[]) {
if (list.length) {
// If the search results are reflected in the table.
// And 20 items are loaded at a time.
if (list.length === 20) {
this.rows = list.map((item) => ({ ...item }));
// Load more items
} else {
const newRows = list.map((item) => ({ ...item })).slice(this.rows.length);
this.rows = this.rows.concat(newRows);
}
}
}

TypeError: Cannot read property 'addEventListener' of null when creating unit test - Jasmine (Angular)

I have unit tests with Jasmine and what I'm getting is this
TypeError: Cannot read property 'addEventListener' of null
The actual code is this...
ngAfterViewInit() {
this.autoCompleteInput = <HTMLInputElement>document.querySelector('.search-input');
this.autoCompleteInput.addEventListener('blur', this.onBlur.bind(this));
this.autoCompleteInput.addEventListener('input', this.onInput.bind(this));
this.autoCompleteInput.addEventListener('focus', this.onFocus.bind(this));
this.renderer.setAttribute(this.inputRef.nativeElement, 'aria-autocomplete', 'both');
if (this.filter !== undefined && this.filter !== null && this.filter !== '') {
this.filter = '';
}
}
The first line of the addEventListener works
this.autoCompleteInput.addEventListener('blur', this.onBlur.bind(this));
but the remaining fail with ng test --code-coverage --watch=false
When I check the report I see this:
What I don't understand is why onBlur tests fine and the rest do not?
Here's my Jasmine code:
import { TestBed, async, ComponentFixture, fakeAsync, tick } from '#angular/core/testing';
import { RouterTestingModule } from '#angular/router/testing';
import { CUSTOM_ELEMENTS_SCHEMA, DebugElement } from '#angular/core';
import { AutocompleteComponent } from './autocomplete.component';
import { filter } from 'lodash';
describe('Auto Complete Component', () => {
let autoCompleteComponent: AutocompleteComponent;
let fixture: ComponentFixture<AutocompleteComponent>;
let autoCompleteInput: HTMLInputElement;
let filteredItems: string[] = [];
let $window, $provide, listeners;
// let rendered: DebugElement;
beforeEach(async(() => {
TestBed.configureTestingModule({
imports: [
RouterTestingModule.withRoutes([])
],
declarations: [
AutocompleteComponent
],
providers: [AutocompleteComponent],
schemas: [CUSTOM_ELEMENTS_SCHEMA]
}).compileComponents().then(() => {
fixture = TestBed.createComponent(AutocompleteComponent);
autoCompleteComponent = fixture.componentInstance;
fixture.detectChanges();
});
}));
it('should create call ngOnChanges ', () => {
jasmine.createSpy('ngOnChanges').and.callThrough();
autoCompleteComponent.ngOnChanges();
expect(autoCompleteComponent.ngOnChanges()).toHaveBeenCalled();
});
it('should create filterItems() Function ', () => {
jasmine.createSpy('filterItems').and.callThrough();
expect(autoCompleteComponent.filterItems).toBeUndefined();
});
it('should create call clearFocus ', () => {
jasmine.createSpy('clearFocus').and.callThrough();
autoCompleteComponent.clearFocus();
expect(autoCompleteComponent.clearFocus()).toHaveBeenCalled();
});
it('should call onBlur Event ', () => {
jasmine.createSpy('onBlur').and.callThrough();
autoCompleteComponent.onBlur(event);
expect(autoCompleteComponent.onBlur(event)).toHaveBeenCalled();
});
it('should call onItemSelect Event ', () => {
let item = '';
jasmine.createSpy('onItemSelect').and.callThrough();
jasmine.createSpy('clearFocus').and.callThrough();
expect(autoCompleteComponent.onItemSelect(event, item)).toHaveBeenCalled();
expect(autoCompleteComponent.itemSelect.emit(item)).toHaveBeenCalled();
expect(autoCompleteComponent.clearFocus()).toHaveBeenCalled();
});
it('should call onFocus Event ', () => {
jasmine.createSpy('onFocus').and.callThrough();
autoCompleteComponent.onFocus(event);
expect(autoCompleteComponent.autoCompleteInput.focus()).toHaveBeenCalled;
// expect(autoCompleteComponent.onFocus(event)).toHaveBeenCalled();
});
it('should call onInput Event ', () => {
jasmine.createSpy('onInput').and.callThrough();
autoCompleteComponent.onInput(event);
expect(autoCompleteComponent.onInput(event)).toHaveBeenCalled();
});
});
After much experimentation, I found the answer and I hope this helps others.
Here's the solution:
ngAfterViewInit() {
this.autoCompleteInput = <HTMLInputElement>document.querySelector('.search-input');
console.log('Add Event Listener: ', this.autoCompleteInput);
this.bindOnBlurStateEventCallback();
this.bindOnInputStateEventCallback();
this.bindOnFocusStateEventCallback();
this.renderer.setAttribute(this.autoCompleteInput, 'aria-autocomplete', 'both');
if (this.filter !== undefined && this.filter !== null && this.filter !== '') {
this.filter = '';
}
}
public bindOnBlurStateEventCallback(): void {
this.autoCompleteInput.addEventListener('blur', this.onBlur.bind(this));
document.querySelector('.search-input').addEventListener('blur', () => {
console.log('You selected: ', this.autoCompleteInput.value);
});
}
public bindOnInputStateEventCallback(): void {
this.autoCompleteInput.addEventListener('input', this.onInput.bind(this));
}
public bindOnFocusStateEventCallback(): void {
this.autoCompleteInput.addEventListener('focus', this.onFocus.bind(this));
}
and in the spec.ts file:
it('adds listener events', function () {
spyOn(document, 'addEventListener').and.callThrough();
spyOn(window, 'addEventListener').and.callThrough();
expect(document.addEventListener.prototype).not.toBeTruthy;
expect(window.addEventListener.prototype).not.toBeTruthy;
expect(document.addEventListener.prototype).toBeTruthy;
expect(window.addEventListener.prototype).toBeTruthy;
});
And there you have it!

this.backPressed is not a function

I implemented it in sample , it works but in my main project it's displaying error message that backPressed is not a function.
backPressed = () => {
setTimeout(function() {
//Put All Your Code Here, Which You Want To Execute After Some Delay Time.
BackHandler.exitApp();
}, 3000);
};
componentWillUnmount() {
BackHandler.removeEventListener("hardwareBackPress", this.backPressed);
}
componentDidMount() {
BackHandler.addEventListener("hardwareBackPress", this.backPressed);
}
static getDerivedStateFromProps(nextProps, prevState) {
const { userdata } = nextProps.UserDetailReducer;
const { UpdatingFailure } = nextProps.UpdateUserImageReducer;
if (UpdatingFailure) {
return {
avatarSource: ""
};
}
if (userdata.kenkoScore != "" && userdata.kenkoScore > 0) {
setTimeout(() => {
AsyncStorage.setItem("SCORE_FETCHED", "Yes");
nextProps.navigation.navigate("TabNavigation");
}, 100);
return null;
} else {
***this.backPressed();***
}
if (userdata) {
return { userDetail: userdata };
}
return null;
}
In componentDidMount it is working but in getDerivedStateFromProps not working
getDerivedStateFromProps is static so this refers to the class itself, not an instance of the class.
Make backPressed static to call it from getDerivedStateFromProps. You'll also need to update componentWillUnmount and componentDidMount to ComponentName.backPressed or this.constructor.backPressed. Note that making backPressed static means you won't be able to access this for props or state in the future.

Why my vue js data member is not getting updated?

Data part
data () {
return {
containsAd: true
}
},
Method that manipulates the data member containsAd
updated () {
let _this = this
window.googletag.pubads().addEventListener('slotRenderEnded', function (event) {
if (event.slot.getSlotElementId() === 'div-gpt-ad-nativead1') {
_this.containsAd = !event.isEmpty // this is false
console.log('Ad Exists? ', _this.containsAd)
}
})
},
Just to check if the value has changed or not.
check () {
let _this = this
setTimeout(function () {
console.log('Current Value', _this.containsAd)
}, 5000)
}
Resulting Output
I think doing the event listener in the mounted hook will sort your issue.
data() {
return {
containsAd: true
};
},
mounted() {
window.googletag.pubads().addEventListener('slotRenderEnded', event => {
if (event.slot.getSlotElementId() === 'div-gpt-ad-nativead1') {
this.containsAd = ! event.isEmpty // this is false
console.log('Ad Exists?', this.containsAd);
}
});
}
Also using es6 shorthand function will avoid you having to set _this.

Computed property not updating on props changes

I can't get a computed property to update, when a nested property in a passed prop object is changed.
this.favourite is passed via props, but the computed property is not updating when this.favourite.selectedChoices.second.id and this.favourite.selectedChoices.first.id is changed.
Any ideas of how to make this reactive?
Here's the computed property:
isDisabled() {
const hasMultipleChoices = this.favourite.choices.length
? this.favourite.choices[0].value.some(value => value.choices.length) :
false;
if (hasMultipleChoices && !this.favourite.selectedChoices.second.id) {
return true;
} else if (this.favourite.choices.length && !this.favourite.selectedChoices.first.id) {
return true;
}
return false;
}
TESTED
In my test.vue
props: {
variant: {
type: String,
default: ''
}
}
const myComputedName = computed(() => {
return {
'yellow--warning': props.variant === 'yellow',
'red--warning': props.variant === 'red',
}
})
test.spec.js
import { shallowMount } from '#vue/test-utils'
import test from '#/components/test.vue'
let wrapper
//default values
function createConfig(overrides) {
let variant = ''
const propsData = { variant }
return Object.assign({ propsData }, overrides)
}
//test
describe('test.vue Implementation Test', () => {
let wrapper
// TEARDOWN - run after to each unit test
afterEach(() => {
wrapper.destroy()
})
it('computed return red if prop variant is red', async (done) => {
const config = createConfig({ propsData: { variant: 'red' } })
wrapper = shallowMount(test, config)
wrapper.vm.$nextTick(() => {
//checking that my computed has changed, in my case I want to matchanObject
expect(wrapper.vm.myComputedName).toMatchObject({
'red--warning': true
})
//check what your computed value looks like
console.log(wrapper.vm.myComputedName)
done()
})
})
//TEST 2 Variant, this time instead red, lets say yellow
it('computed return yellow if prop variant is red', async (done) => {
const config = createConfig({ propsData: { variant: 'yellow' } })
wrapper = shallowMount(test, config)
wrapper.vm.$nextTick(() => {
//checking that my computed has changed, in my case I want to matchanObject
expect(wrapper.vm.myComputedName).toMatchObject({
'yellow--warning': true
})
//check what your computed value looks like
console.log(wrapper.vm.myComputedName)
done()
})
})
})
for more info, this page helped me.
https://vuejsdevelopers.com/2019/08/26/vue-what-to-unit-test-components/
The reason why the computed property didn't update, was because I created the id object of both this.favourite.selectedChoices.second and this.favourite.selectedChoices.first, after the component was rendered. Declaring the id objects before render was the solution.