setTimeout inside component is getting called regardless of page - react-native

I have a setTimeout call that gets called every 5 minutes. The issue is that no matter what page I am on, the timeout is still getting called and is making api calls.
My setTimeout component is inside the home page, what would be ideal is killing just that component when no longer on the home page. I would like to avoid destroying the homepage component and not having to refetch data.
My setTimeout code is like this:
sendCords(){
this.props.actions.findCords()
this.beginTimeout()
}
beginTimeout(){
let timer = setTimeout(this.sendCords,300000);
this.setState({timer});
}
Note: Lifecycle hooks E.G. componentWillUnMount is not getting called, as the pages are like a stack - and the pages are not un-mounting. I am using react-native-router-flux
Any help would be much appreciated.

Well I ended up having to do a few things, in my actions I would check what page I was calling and dispatch an empty action if It was not called on the homepage. This would trigger a the clear timeout. Having a force refresh on my component was needed
<Comp refresh={() => this.setState({val:!this.state.val} />
And I would then I have a shouldComponentUpdate used like so when navigating back to the home page and needing to set the timeout again:
shouldComponentUpdate(nextProps, nextState){
if(this.props.removeTimer && !nextState.removeTimer){
this.timeOutFunc()
}

Related

Is it possible to cancel all running JS functions when destroying a Vue component?

I'm wondering if it's possible to cancel all running async functions belonging to a component when destroying that component. I have a View-component which fetches a lot of data when the user enters that page, the problem is if the user goes to another page before the data is fully loaded, then the request-queue-limit is reached and slows down the data-loading for the new page.
What I did to fix this was to just check the lifecycle-status of the component instance. I found out that it was possible to check this._isBeingDestroyed
and this._isDestroyed, and then do an early return.
async fetchDataFunction() {
if (this._isBeingDestroyed || this._isDestroyed) return;
// Code
}

How to run a callback when vue router-link finished navigation

What I want to do is - the user clicks the router-link - this does not actually do a navigation but just refreshes the page with new data. This is no good for accessibility because the user does not know a navigation happened, but good for performance because full navigation not required.
So I would like some way to solve that problem.
The way I might naively expect to solve the problem is wait for navigation to be over and run a callback, or use a promise and when promise completes run code. The code running when navigation over would put the focus on some element at navigation finished.
I was hoping I could do something obvious like the following
<router-link :to="(router) => {
router.push('/').onComplete(() => {
code to set focus here
});
}"
but it doesn't look like that is possible.
How should I solve my problem, as close to this solution as possible please.
This sounds like you might be using the wrong tools for the job. If you aren't actually navigating, there's no good reason to use router link - if you purely want to have the aesthetics of a link, use <a>. And if you are just expecting data to be refreshed, don't use router.push but simply call the function you want by attaching a listener to the link. If you want to show some kind of loading animation during the data fetching, you could either just set a variable, or use a library like vue-wait
In your case this could be something like:
<a #click="onClick">Link to click</a>
...
data(){
return {
isLoading:false
}
}
methods:{
async onClick(){
this.isLoading=true
await fetch(...)
this.isLoading=false
}
}
To answer your original question as well - yes, it's possible to run code when a navigation is finished. There's quite a few ways to do it, but if you want to specifically run code after a router.push, you can do that - router.push is a promise. So router.push(...).then(...).catch() works as well

asyncData hook when hard refreshing in Nuxt

I just realized that the asyncData hook is not called when hard refreshing the page. But I have important data to load to show on that page. And I want to make sure that they are always available, even when the user hard refreshes the page.
asyncData from the documentation
the promise returned by the asyncData hook is resolved during route transition
In that case, the best way is to use the fetch() hook and display a loader while you do finish your calls thanks to the $fetchState.pending helper.
Actually, I do think that fetch() is better in many ways.
Quick article on the subject: https://nuxtjs.org/blog/understanding-how-fetch-works-in-nuxt-2-12/
The one on the bottom of the page (Sergey's) is cool with some practical example of a nice implementation too.
You could also use this somewhat hacky solution in a layout to see if the initial location (the one you are when you hard refresh) is the one you want to be. Basically, if you land on a specific page (hard refresh or following a new window page for example) but want to have some custom behavior.
beforeCreate() {
if (!['some-other-page'].includes(this.$router.history._startLocation)) {
this.$router.replace({ name: 'index' }).catch(() => {})
}
},
Still, this one infinite loops if used in a middleware (or I made a mistake) and it's less clean than a fetch() hook.

NUXT VUE Transition in component when leaving page

I got the following setup in nuxt
page/blog/index.vue
components/topheader.vue
I would like to have transition effect when you leave a page and enter the page in the component topheader. The title should fadein/fadeout. This because now the title is replaced very abrupt without a transition effect.
The problem is when you go to a new page/route the animation has no time to go ahead. So I have some success with stopping the the router with beforeRouteLeave then pass a prop "showTitle" to the component setting it to false. Set a timeout on the next() in beforeLeave ...
But this feels quite wrong and bad practice
I Looked in to setting in nuxt.conf transition. But this is for the a page transition and has only an effect on the complete page. It seems I can't target something in a component only there. My feeling is I should be able to do this with some setting there. However I'm missing something.
For appearing the transition I can use ...
Now my question. How to target something in a component of a page to create a transition on leaving the page. Ideal the loading is already started so the transition takes about the time between the page loads.
thx in advance
You can wrap your component with the <transition name="yourTransitionName"></transition> tag.
In CSS:
.yourTransitionName-leave-active {
/* your code */
}

show loading spinner until all child components inside of a Page have been rendered - Nativescript

I'm trying to show an activity indicator, when I go from one page to another. The target page contains many components within it, and it takes time to load. that's why I need some way to listen when all the child components are loaded, and at that moment tell my variable isBussy to be false
<template>
<StackLayout>
<ActivityIndicator :busy="isBussy" v-if="isBussy" />
<StackLayout v-else>
<Component1 />
<Component2 />
<Component3 />
<Component4 />
</StackLayout>
<StackLayout>
</template>
<script>
import Component1 from '~/components/Component1'
import Component2 from '~/components/Component2'
import Component3 from '~/components/Component3'
import Component4 from '~/components/Component4'
export default {
data() {
return {
isBussy: true
}
},
mounted() {
this.$nextTick(function() {
// Code that will run only after the
// entire view has been re-rendered
this.isBussy = false
})
}
}
</script>
this code does not work, since once the navigation is indicated from the previous page with:
#tap="$goto('otherPage', { props: { foo: bar } })"
it remains stuck on the initial page, and all the components begin to load in the background of the destination page, but without displaying the parent page, changing to this, only when the whole process ends, and never show/hide the activity indicator as expected.
By the way this expected behavior works perfectly when i do request and process them with Promises, then I turn on or off a variable in the state and it works. but I can not replicate that behavior in the navigation between pages and listen to load all the components
EDIT
Finally I achieved the desired behavior with a little trick I found on the internet
mounted() {
setTimeout(() => {
this.isBussy = false
}, 500)
},
this causes that the rendering of all the children components is delayed only a little, so that the activity indicator is shown, but not too much to produce that none of the components contained in the else block is detected and begin to rendering
There are two main ideas to understand here I think. I'll describe both.
1. General technique to Fetch Data without blocking render
It sounds like you understand this concept at the parent component level but then are asking how to do something very similar for the child components that this page contains.
The way I handle this, is in my component, I have my data default to an isLoading state. Then, in beforeMount() or mounted(), I perform my asynchronous actions and make necessary changes to my page's data.
The problem becomes entirely recursive when we look at child components. You want to make sure your child components are rendering and that any long running data fetching that needs to occur within their implementation will simply cause them to re-render once that fetching is complete.
Here is a working example: https://codesandbox.io/embed/r4o56o3olp
This example uses Nuxt. Aside from the addition fetch() and asyncData() methods, the rest of the Vue lifecycle hooks are the same here.
I use new Promise and setTimeout to demonstrate an operation that would use promises and be asynchronous. (e.g. axios.get(..))
The About page loads, and the beforeMount() lifecycle hook performs the asynchronous fetching in a way that doesn't block the page from rendering.
I use the beforeMount() hook because, according to here ( https://alligator.io/vuejs/component-lifecycle/ ), it is the first lifecycle hook that we have access to once the page's data is reactive. (So modifying this.myDataProp would trigger a re-render if {{ myDataProp }} was used in the template).
I also included a child component where I purposely made its data take twice as long to load. Since I again, am letting the component render immediately, and then I handle the fetching/updating of data in an appropriate lifecycle hook, I can manage when the end-user perceives a page to be loaded.
In my working example, the LongLoadingComponent did the same exact technique as the About page.
Once you see how to use beforeMount() or mounted() to fetch data and then update state, I think the trick is to take a moment and really think about the default state of your component. When it first renders, what should the user see before any of it's data fetching/long-running operations are completed?
Once you determine what your default (not yet loaded) component should look like, try getting that to render on your screen, and secondarily add in the logic that fetches and updates state data.
2. Listening for when a Child Component is finished rendering from a parent component
This makes use of the above technique, but includes the usage of the updated() hook and emitting a custom event ( https://v2.vuejs.org/v2/guide/components-custom-events.html
)
If you really want to listen for when your child components are finished rendering, you can $emit a custom event in your updated() hook. Perhaps something like this (in one of your child components)
if (this.dataLoaded) { this.$emit('loadedAndRendered') }
So when the child's async operations are done, it can flip it's dataLoaded property to true. If dataLoaded is used in the child's <template> somewhere, then the component should re-render (for it's "finished" state). When the child re-renders, the updated() hook should trigger. (again, see: https://alligator.io/vuejs/component-lifecycle/ ) I included the if (this.dataLoaded) part just to handle case where updated() hook might be called during intermediate data updates. (We only want to emit loadedAndRendered event if child is finished loading data/updating.)
3. Other caveats about universal nuxt applications
It wasn't until after I wrote this answer that I realized you aren't using Nuxt. However I'm adding this in case other Nuxt users happen to come across this.
I'm adding this section just because it took some focused hands-on time for me to wrap my head around. A Nuxt Universal Application does both server-side and client-side rendering. Understanding when something renders on the client vs when it was rendered on the server was a little difficult for me at first. In the working example I linked above, when you visit the about page you can also see if that component was fetched from the server or if it was just rendered by the client.
I'd recommend playing with a Page's fetch() and asyncData() methods and see how it impacts when certain things render on your screen. ( https://nuxtjs.org/api/pages-fetch/ ) ( https://nuxtjs.org/api/ ). Seeing what these methods are useful for helps me also identify what they are not useful for.
If you're using a Vuex store, I'd recommend seeing what happens when you refresh a page or use instead of a to navigate between pages. (Seeing something like the SSR schema diagram can be helpful here: https://nuxtjs.org/guide#schema )
..I have yet to fully appreciate the details of the bundling and delivery behavior that Webpack provides for a Universal Nuxt app (See right side of diagram here: https://medium.freecodecamp.org/universal-application-code-structure-in-nuxt-js-4cd014cc0baa )