I am currently using the following Libraries:
react-native-version-check
react-native-navigation (By Wix)
I would like to ask, what is the best practice on what event should I use in "react-native-navigation" to do a "react-native-version-check"? I created multiple pages using hooks, and ideally would not like to use the "UseEffect" in order to check the app version if it's the latest.
I have attached my code below, this is during registering all the app screen:
Navigation.events().registerCommandCompletedListener(async (event) => {
try {
console.log('Version Check Attempting');
let current = await VersionCheck.getCurrentVersion();
let latest = await VersionCheck.getLatestVersion();
let response = await VersionCheck.needUpdate({
currentVersion: current,
latestVersion: latest,
});
if (isChecked) { return }
if (response.isNeeded) {
Navigation.showOverlay({
component: {
name: "UpdateRequired",
options: {
layout: {
componentBackgroundColor: 'transparent'
},
},
},
});
isAllModalDismissed = false
isChecked = true
} else {
if(isChecked === false && isAllModalDismissed === true) {
isAllModalDismissed = true;
await Navigation.dismissAllOverlays();
}
}
} catch(error) {
console.log(error)
} finally {
console.log('Version Check Finished');
}
})
Related
I use react-native with graphql.
I have a query and tried to use refetch.
const { data: updatePhoto, refetch } = useQuery(SEE_PHOTO_QUERY, {
variables: {
id: photoId,
},
});
when after I edit my comment, I want to refetch this query and put it on setState in order to change UI.
const onEditValid = async ({ comments }) => {
const commentId = await AsyncStorage.getItem("#commentId");
await editCommentMutation({
variables: {
id: parseInt(commentId),
payload: comments,
},
update: updateEditComment,
});
};
const updateEditComment = async (cache, result) => {
const {
data: {
editComment: { error, ok, id },
},
} = result;
if (ok) {
const commentId = await AsyncStorage.getItem("#commentId");
const { comments } = getValues();
await textRef.current.clear();
await refetch();
setState(updatePhoto);
await cache.modify({
id: `Comment:${commentId}`,
fields: {
payload(prev) {
return comments;
},
},
});
}
};
But UI doesn't change.
I tried to change UI by modifying cache and refetching data. But both fails for a week.. :(
I also raised the question about fail of cache modify
=> React Native: `cache.modity` doesn't work
But no one answers.
I really need your help.. please help me
I am trying to mock a setInterval inside my created hook but no matter what I try
the function is never called. What I have done so far is using jest.useFakeTimers and inside
each test I would use jest.advanceTimersByTime(8000) to check if my api is being called.
I would appreciate any opinions/help. thanks
my vue file
created() {
setInterval(() => this.checkStatus(), 8000)
},
methods: {
async checkStatus() {
let activated = false
if (!this.isLoading) {
this.isLoading = true
let res = await this.$UserApi.getUserActivateStatus(this.accountId)
this.isLoading = false
if (res.success) {
activated = res.activated
}
if (activated) {
console.log("activated")
} else {
console.log("error")
}
}
}
}
my test file
import { shallowMount, config } from "#vue/test-utils"
import Step4 from "../../../login/smart_station/step4"
describe("Step4", () => {
let wrapper
const $route = {
query: {
account_id: "99"
}
}
const mockGetUserActivateStatus = jest.fn(() =>
Promise.resolve({ success: true, activated: true })
)
beforeEach(() => {
wrapper = shallowMount(Step4, {
mocks: {
$UserApi: {
getUserActivateStatus: mockGetUserActivateStatus
}
}
})
jest.useFakeTimers()
})
it("activates status every 8secs", async () => {
jest.advanceTimersByTime(9000)
expect(mockGetUserActivateStatus).toHaveBeenCalled()
})
})
Jest's Timer Mocks replace the native timer functions like setInterval with their own versions that can be controlled.
Your problem is that you are telling Jest to replace these functions after your component is created and mounted. Since you're using setInterval within your component's created hook, this will still be using the real version.
Move the jest.useFakeTimers() to the top of the beforeEach setup function
beforeEach(() => {
jest.useFakeTimers()
wrapper = shallowMount(Step4, {
mocks: {
$UserApi: {
getUserActivateStatus: mockGetUserActivateStatus
}
}
})
})
I'm attempting to set a loading status on a component which will display a loading graphic while the request is being processed. I have this working with a call to an API, returning a promise from a fetch to a REST interface. However, when attempting this with a simple call to a service it only seems to call the last mutation
In the vuex store:
var initialState = {
status: { loading: false },
all_clients: [],
current_client: {
loaded: false,
}
}
export const fund = {
namespaced: true,
state: initialState,
actions: {
getClientOverview({ commit }, client_group_id) {
commit('loadingRequest');
clientService.getClientOverview(client_group_id)
.then(
clientInfo => {
commit('loadingSuccess')
},
error => {
commit('loadingError', error);
}
)
}
},
mutations: {
// Mutations to set loading and error statuses
loadingRequest(state) {
state.status = { loading: true };
},
loadingSuccess(state) {
state.status = { loading: false };
},
loadingError(state,error) {
state.status = { loading: false };
store.dispatch('alert/error', "Error Loading Client: " + error)
},
}
and in the corresponding client service that is called:
function getClientOverview(client_group_id) {
return new Promise((resolve,reject) => {
try {
// Note here that client.state.all_clients is an array of objects already set in the store
let clientDetail = client.state.all_clients.filter(function(item) {
return item.client_group_id === client_group_id;
});
// THIS PAUSE CODE JUST ADDED TO SLOW THINGS DOWN A BIT ON FRONT END
// SO I CAN SEE IF MUTATIONS ARE WORKING CORRECTLY
var d = new Date();
var d2 = null;
do { d2 = new Date(); }
while(d2-d < 2000);
// TO HERE
if(clientDetail.length == 0){
reject("Client Information not found")
}
resolve(clientDetail[0])
}catch(error){
reject(error)
}
})
}
A client is being returned as expected, as a resolved promise, but I only see 'loading' being set to false on the front end, it doesn't set to true while the service is running its process.
If I remove the commit('loadingSuccess') line then I can see the original commit being called as expected and loading being set to true - it seems as though only one commit is being called per action
Any help with this would be gratefully appreciated!
Thanks
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.
This is the flow of the application:
The shell.js loads the schoolyeardialog.js which contains the schoolyearbrowser.js which loads the schoolyearwizard.js via create or edit button.
When I repeat these steps multiple times: click create/edit button then I do multiple
requests in my SchoolyearWizard to this:
$.when(service.editSchoolyear(schoolyearId))
The reason is that the subscribed events are not correctly unsubscribed in my opinion.
I have tried different ways of unsubscribing in the SchoolyearDialog.js file.
Either the events did not fire - when I did the subscription.off(); after the app.on(...)
or It was unsubscribed at the wrong position.
Where should I unsubscribe correctly?
If you guys need a sample repo as visual studio solution I can provide this if it helps or maybe you see clearly and immediately the error?!
I have also thought about unsubscribing from the 2 events create/edit when the SchoolyearDialog module is "unloaded" because then both events could/would be unsubscribed not only the create OR edit subscription as it is now when I either click the add or edit button... how would I do that?
SHELL
define(['plugins/router', 'durandal/app', 'viewmodels/SchoolyearDialog', 'knockout'], function (router, app, schoolyearDialog, ko) {
self.schoolyearIsLoaded = ko.observable(false);
var saveTimeTableSubscription = app.on('savedTimeTable').then(function (options) {
// after coming the 2nd time here
if (!self.schoolyearIsLoaded()) {
router.map([{ route: 'lessonplanner', moduleId: 'viewmodels/lessonplanner', title: 'lesson planner', nav: true },
{ route: 'documentbrowser', moduleId: 'viewmodels/documentbrowser', title: 'document browser', nav: true }])
.buildNavigationModel();
self.schoolyearIsLoaded(true);
}
router.navigate("lessonplanner", true);
});
return {
router: router,
activate: function () {
router.map([{ route: '', moduleId: 'viewmodels/SchoolyearDialog', nav: true, title: 'Schoolyearbrowser' }
]).buildNavigationModel();
return router.activate('SchoolyearDialog');
}
};
});
SchoolyearDialog
define(['durandal/app', 'knockout', 'plugins/router', 'viewmodels/SchoolyearWizard'],
function (app, ko, router, wizard) {
var ctor = function () {
debugger;
var self = this;
self.createSubscribe = ko.observable();
self.editSubscribe = ko.observable();
self.activeScreen = ko.observable('viewmodels/SchoolyearBrowser'); // set the schoolyear browser as default module
var createWizardSubscription = app.on('createWizard').then(function () {
self.createSubscribe().off();
self.createSubscribe(null);
self.activeScreen(new wizard('create'));
}, self);
self.createSubscribe(createWizardSubscription);
var editWizardSubscription = app.on('editWizard').then(function (schoolyearId) {
self.editSubscribe().off();
self.editSubscribe(null);
self.activeScreen(new wizard('edit', schoolyearId));
}, self);
self.editSubscribe(editWizardSubscription);
}
return ctor;
});
SchoolyearBrowser
define(['durandal/app', 'plugins/dialog', 'knockout', 'services/dataservice', 'plugins/router'],
function (app, dialog, ko, dataservice, router) {
var SchoolyearBrowser = function () {
var self = this;
self.schoolyears = ko.observableArray();
$.when(dataservice.getSchoolyears())
.done(function (schoolyearModels) {
self.schoolyears(schoolyearModels);
});
self.create = function () {
app.trigger('createWizard');
}
self.edit = function () {
app.trigger('editWizard', 1);
}
};
return SchoolyearBrowser;
});
SchoolyearWizard
define(['durandal/activator', 'viewmodels/step1', 'viewmodels/step2', 'knockout', 'durandal/app', 'services/dataservice', 'viewmodels/CreateEditSchoolyearViewModel'],
function (activator, Step1, Step2, ko, app, service, CreateEditSchoolyearViewModel) {
var ctor = function (viewMode, schoolyearId) {
debugger;
// depending on the mode I could setup 2 different step modules for create and edit ? and the Wizard has one property called content
if (viewMode === 'edit') {
$.when(service.editSchoolyear(schoolyearId))
.done(function (response) {
debugger;
self.viewModel(new CreateEditSchoolyearViewModel(response));
}).fail(function (error) {
alert(error);
});
}
else if (viewMode === 'create') {
$.when(service.createSchoolyear())
.done(function (response) {
debugger;
self.viewModel(new CreateEditSchoolyearViewModel(response));
}).fail(function (error) {
alert(error);
});
}
var self = this;
var steps = [new Step1(viewMode), new Step2(viewMode)];
var step = ko.observable(0); // Start with first step
self.activeStep = activator.create();
var stepsLength = steps.length;
self.viewModel = ko.observable();
this.hasPrevious = ko.computed(function () {
return step() > 0;
});
self.caption = ko.observable();
this.activeStep(steps[step()]);
this.hasNext = ko.computed(function () {
if ((step() === stepsLength - 1) && self.activeStep().isValid()) {
// save
self.caption('save');
return true;
} else if ((step() < stepsLength - 1) && self.activeStep().isValid()) {
self.caption('next');
return true;
}
});
this.isLastStep = function () {
return step() === stepsLength - 1;
}
this.next = function () {
if (this.isLastStep()) {
var vm = this.activeStep(); //.viewModel;
$.when(service.saveCreateSchoolyear({ schoolyearId: 1 })).done(function () {
app.trigger('savedTimeTable', { isSuccess: true });
}).fail(function (e) {
alert(e);
});
}
else if (step() < stepsLength) {
step(step() + 1);
self.activeStep(steps[step()]);
}
}
this.previous = function () {
if (step() > 0) {
step(step() - 1);
self.activeStep(steps[step()]);
}
}
}
return ctor;
});
This helped me greatly:
activator.deactivate function allows the previous object to execute custom deactivation logic."
SchoolyearDialog.js
self.deactivate = function () {
self.createSubscribe().off();
self.editSubscribe().off();
}
When the schoolyearDialog is deactivated both events are unsubscribed independing wether button create/edit is clicked. This is for me a clean solution :)
I agree with your solution but I'd recommend not to use plain .off() without parameters as this will cause to deregister all the events in the application.
Rather pass the event name as a parameter to your off method:
self.createSubscribe().off('savedTimeTable');