It is so slow when a callback function be called repeatedly in react native app - react-native

It will have a callback function called repeatedly to when I start a download task. But It will be so slow that it can't give feedback when touch a button.
Fileio.downloadFile(downloadData[downloadFileIndex].uri, '1.jpg',this.progressFunc.bind(this)).then((DownloadResult)=> {
if (DownloadResult.statusCode == 200) {
let nextDownloadFileIndex = this.props.downloadFileIndex + 1;
this.props.dispatch(DOWNLOADED_A_FILE({
downloadFileIndex:nextDownloadFileIndex,
progressNum:0
}))
}
}).catch((error)=> {
console.log(error)
})
This is my code and the callback function are as be folllowed
progressFunc(DownloadBeginCallbackResult) {
let progressNum = DownloadBeginCallbackResult.bytesWritten / DownloadBeginCallbackResult.contentLength;
if(progressNum<=0.99){
this.props.dispatch(DOWNLOADING_A_FILE({
progressNum:progressNum,
jobId:this.props.jobId
}));
}else{
this.props.dispatch(DOWNLOADING_A_FILE({
progressNum:0,
jobId:this.props.jobId
}));
}
}
I mean I can't get feedback immediately when I touch button. I think that it is because I have a callback function called repeatedly. so js can't handle so many tasks;

It does sound like JS thread is busy doing the request and not able to communicate back to UI thread. One thing you can try is to wrap you on press handler in an InteractionManager.runAfterInteractions(() => ...)
See https://facebook.github.io/react-native/docs/interactionmanager.html

Related

How to remove a specific notification forever using react-native-push-notification

I am currently using the react-native-push-notification library to schedule and receive notifications in my React Native app. I am able to cancel a scheduled notification using the cancelLocalNotification method, but this only cancels the notification for 24 hours. I want to find a way to remove a specific notification forever, so it will not be rescheduled.
I have tried using the following code to cancel a notification by its ID, but it only cancels it for 24 hours:
const onCancelNotification = async (id: string) => {
// Get a list of all scheduled notifications
PushNotification.getScheduledLocalNotifications((notifications) => {
// Iterate through the list of notifications
notifications.forEach((notification) => {
// Check if the notification is the one you want to cancel
if (notification.id.indexOf(id) === 0) {
// Cancel the notification
PushNotification.cancelLocalNotification(notification.id);
}
});
});
};
I would greatly appreciate any help or suggestions on how to achieve this.
This code snippet demonstrates a workaround for removing a specific scheduled local notification in React Native. The function onRemoveNotification takes in an id parameter, which is used to identify the specific notification that needs to be removed.
It's important to note that there is no direct method for removing a specific scheduled local notification in React Native. This code provides a workaround that can be used, but it's important to be aware that it relies on scheduling a notification with an earlier date and setting the repeatType to undefined.
Please note that this code is not a perfect solution and could have side effects on the app.
const onRemoveNotification = async (id: string) => {
// Get a list of all scheduled notifications
PushNotification.getScheduledLocalNotifications((notifications) => {
// Iterate through the list of notifications
notifications.forEach((notification) => {
// Check if the notification is the one you want to cancel
if (notification.data.notificationId?.indexOf(id) === 0) {
// Create a new date one day earlier than the current scheduled date
const earlyDate = moment(notification.date).add(-1, "day").toDate();
// remove the notification
// schedule the notification with an earlier date and repeat type undefined
// this will effectively "remove" the notification
// since it will not be displayed
PushNotification.localNotificationSchedule({
id: notification.id,
title: notification.title,
message: notification.message,
repeatType: undefined,
date: earlyDate,
});
// cancel the previous scheduled notification
PushNotification.cancelLocalNotification(notification.id);
}
});
});
};

Ionic 3 infinite-scroll simulate in e2e test jasmine/protractor

If you go here: http://ionicframework.com/docs/api/components/infinite-scroll/InfiniteScroll/
Inspect the demo and click the last item on the list:
Then in the console type: $0.scrollIntoView()
Infinite Scroll is never triggered.
Is there a way to programmatically trigger infinite-scroll in protractor context?
The implementation of the scroll in your example rely on the speed/velocity of the scroll which I guess falls far from the expected range when scrollIntoView is called.
One workaround is to simulates a smooth scroll by emitting multiple scroll events over a reasonable time. The idea is to reproduce as close as possible the behavior of a real user.
Some browsers already provides the option via scrollIntoView (supported by Chrome 62) :
$0.scrollIntoView({behavior: "smooth", block: "end"});
Using the accepted answer, in my case, I used ion-infinite-scroll as the argument.
Complete test to check if more content is loaded in Ionic:
describe('Scroll', () => {
it('should load more when reached end', async () => {
let list = getList();
let currentCount = await list.count();
const refresher = element(by.tagName('ion-infinite-scroll')).getWebElement();
let count = 0;
while(true){
browser.executeScript(`arguments[0].scrollIntoView({behavior: "smooth", block: "end"});`, refresher);
browser.sleep(1000); // wait for data to be loaded from api
list = getList();
let newCount = await list.count();
expect(newCount).toBeGreaterThanOrEqual(currentCount)
expect(newCount).toBeLessThanOrEqual(currentCount * 2)
if(newCount === currentCount){
break;
}
currentCount = newCount;
count++;
}
expect(count).toBeGreaterThan(0);
})
});
function getList() {
return element(by.className(pageId + ' list')).all(by.tagName('ion-item'));
}

backbone view in router lost after creation

When I try to associate my router's public variable this.currentView to a newly created view, the view gets lost, the public variable is null instead of containing the newly created view.
var self=this;
var watchListsCollection = new WatchlistCollection;
watchListsCollection.url = "watchlists";
user.fetch().done(function() {
watchListsCollection.fetch().done(function () {
loggedUser.fetch().done(function () {
self.currentView = new UserView(user, watchListsCollection,loggedUser);
});
});
});
alert(this.currentView); //null
The fetch() calls you do are firing asynchronous AJAX requests, meaning the code in your done handlers are not going to be executed untill the server calls return. Once you've executed user.fetch() the browser will fire off a request and then continue running your program and alert this.currentView without waiting for the requests to finish.
The sequence of events is basically going to be
call user.fetch()
alert this.currentView
call watchListsCollection.fetch()
call loggedUser.fetch()
set the value of self.currentView
You will not be able to see the value of your currentView before the last server request have completed.
If you change your code to
var self=this;
var watchListsCollection = new WatchlistCollection;
watchListsCollection.url = "watchlists";
user.fetch().done(function() {
watchListsCollection.fetch().done(function () {
loggedUser.fetch().done(function () {
self.currentView = new UserView(user, watchListsCollection,loggedUser);
alertCurrentView();
});
});
});
function alertCurrentView() {
alert(this.currentView);
}
You should see the correct value displayed. Now, depending on what you intend to use your this.currentView for that might or might not let you fix whatever issue you have, but there's no way you're not going to have to wait for all the requests to complete before it's available. If you need to do something with it straight away you should create your UserView immediately and move the fetch() calls into that view's initialize().
fetch() is asynchronous, but you check your variable right after you've started your task. Probably these tasks, as they supposed to be just reads, should be run in parallel. And forget making a copy of this, try _.bind instead according to the Airbnb styleguide: https://github.com/airbnb/javascript
var tasks = [];
tasks.push(user.fetch());
tasks.push(watchListsCollection.fetch());
tasks.push(loggedUser.fetch());
Promise.all(tasks).then(_.bind(function() {
this.currentView = new UserView(user, watchListsCollection, loggedUser);
}, this));
or using ES6 generators:
function* () {
var tasks = [];
tasks.push(user.fetch());
tasks.push(watchListsCollection.fetch());
tasks.push(loggedUser.fetch());
yield Promise.all(tasks);
this.currentView = new UserView(user, watchListsCollection, loggedUser);
}

Youtube API event on a specified time

Is it possible through the YouTube API to fire an event when the video reaches a specified time? e.g. when the video reaches 20 sec. fire the event.
Thanks,
Mauro
not sure if you still need an answer to this (as I'm finding it 4 months later) but here's how I accomplished this with youtube's iframe embed api. It's ugly in that it requires a setInterval, but there really isn't any kind of "timeupdate" event in the YouTube API (at least not in the iframe API), so you have to kind of fake it by checking the video time every so often. It seems to run just fine.
Let's say you want to start up your player as shown here with YT.Player(), and you want to implement your own onProgress() function that is called whenever the video time changes:
In HTML:
<div id="myPlayer"></div>
In JS:
// first, load the YouTube Iframe API:
var tag = document.createElement('script');
tag.src = "//www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
// some variables (global here, but they don't have to be)
var player;
var videoId = 'SomeYoutubeIdHere';
var videotime = 0;
var timeupdater = null;
// load your player when the API becomes ready
function onYoutubeIframeAPIReady() {
player = new YT.Player('myPlayer', {
width: '640',
height: '390',
videoId: videoId,
events: {
'onReady': onPlayerReady
}
});
}
// when the player is ready, start checking the current time every 100 ms.
function onPlayerReady() {
function updateTime() {
var oldTime = videotime;
if(player && player.getCurrentTime) {
videotime = player.getCurrentTime();
}
if(videotime !== oldTime) {
onProgress(videotime);
}
}
timeupdater = setInterval(updateTime, 100);
}
// when the time changes, this will be called.
function onProgress(currentTime) {
if(currentTime > 20) {
console.log("the video reached 20 seconds!");
}
}
It's a little sloppy, requiring a few global variables, but you could easily refactor it into a closure and/or make the interval stop and start itself on play/pause by also including the onStateChange event when you initialize the player, and writing an onPlayerStateChange function that checks for play and pause. You'd just need to seperate the updateTime() function from onPlayerReady, and strategically call timeupdater = setInterval(updateTime, 100); and clearInterval(timeupdater); in the right event handlers. See here for more on using events with YouTube.
I think you may have a look at popcorn.js.
It's an interesting mozilla project and it seems to solve your problem.
Not sure if anyone agrees here but I might prefer to use setTimeout() over setInterval() as it avoids using event listeners, eg:
function checkTime(){
setTimeout(function(){
videotime = getVideoTime();
if(videotime !== requiredTime) {
checkTime();//Recursive call.
}else{
//run stuff you want to at a particular time.
//do not call checkTime() again.
}
},100);
}
Its a basic pseudocode but hopefully conveys the idea.

How to register an event handler on a plugin in YUI3

Given the code below, is there a better way to register an event handler on the resize plugin? Thanks!
var target = Y.Node.create('<div class="rich-text-container"></div>');
// ...
target.plug(Y.Plugin.Resize,{
wrap : true
});
target[Y.Plugin.Resize.NS].on('resize:end',function (e) {
debugger;
// This runs, but is there a better way?
});
target.resize.on('resize:end',function (e) {
alert('this is correct');
});
Y.Plugin.Resize.NS points to the string 'resize' and indicates where on the plugin host the plugin instance will be stored. Derp.