Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Maximum call stack size exceeded on Animate #118

Closed
Magnai1030 opened this issue Dec 27, 2018 · 22 comments
Closed

Maximum call stack size exceeded on Animate #118

Magnai1030 opened this issue Dec 27, 2018 · 22 comments

Comments

@Magnai1030
Copy link

When i use animate component in Developer mode it works fine but In Production mode the error appears. And i removed my all animate:view instead one animate component from my template then it worked. What should i do ?
My Template:

...
<animated:view class="scrolledContainer" :style="{backgroundColor:'rgba(247,247,247,'+JSON.stringify(testColor)+')'}">
  <view :style="{height:statusBarHeight,width:'100%'}"/>
  <animated:view class="headerContainer" :style="{opacity:transparentHeader,height:transparentHeight}">
    ...
  </animated:view>
  <animated:view class="scrolledHeader" :style="{opacity:whiteHeader,height:whiteHeight}">
    <animated:text class="headerTitleTextStyle" :style="{fontSize:titleFont,opacity:titleColor}">{{data.name}}</animated:text>
   </animated:view>
</animated:view>
...

So i reduced like:

...
<animated:view class="scrolledContainer" :style="{backgroundColor:'rgba(247,247,247,'+JSON.stringify(testColor)+')'}">
  <view :style="{height:statusBarHeight,width:'100%'}"/>
</animated:view>
...

So i think it has to be only one animate component in a screen, Or i have to write React native component
My Defendencies

"dependencies": {
    "expo": "29.0.0",
    "i18next": "12.1.0",
    "native-base": "2.8.1",
    "react": "16.5.0",
    "react-i18next": "8.3.8",
    "react-native": "0.55.4",
    "react-navigation": "3.0.4",
    "vue-native-core": "0.0.8",
    "vue-native-helper": "0.0.9",
    "vuelidate": "0.7.4",
    "vuex": "3.0.1",
    "vuex-persist": "2.0.0"
  },
@SaraTV9
Copy link

SaraTV9 commented Mar 12, 2019

Got the same error 😓
@Magnai1030 Any news on this ? Or any tricks ?

@neeraj-singh47
Copy link
Contributor

@SaraTV9 Is it necessary for you to have a nested animated view?

@SaraTV9
Copy link

SaraTV9 commented Mar 14, 2019

@neeraj-singh47 well, I animate an opacity to render smoothly elements on transition page.
You mean that it works on simple element but not nested? Is it specific to vue-native ?

@Magnai1030
Copy link
Author

I removed half of my animation code and replaced with pure react native components. I just avoided to use vue native animation components. i dont think it was solution but it worked for me.

@SaraTV9
Copy link

SaraTV9 commented Mar 15, 2019

@Magnai1030 and how do you do that ?

My vue-native code:

<template>
    <view :style="{ flex: 1, backgroundColor: 'black'}">
        <animated:view class="container" :style="{opacity: animateOpacity}">
            <text class="title">MyComponent</text>
            <text class="text">Test for animate a group</text>
        </animated:view>
    </view>
</template>

<script>
import { Animated, Easing } from 'react-native'

export default {
    data: function() {
        return {
            animateOpacity: new Animated.Value(0)
        };
    },
    methods: {
        animateIn() {
            Animated.timing( 
                this.animateOpacity,
                {
                toValue: 1,
                easing: Easing.easeInOut,
                duration: 1200,
                }
            ).start();     
        }
    },
    mounted () {
        this.animateIn()
    }
};
</script>

Try to pass React Native component directly:

<template>
    <view :style="{ flex: 1, backgroundColor: 'black'}">
        <Animated.View class="container" :style="{opacity: animateOpacity}">
            <text class="title">MyComponent</text>
            <text class="text">Test for animate a group</text>
        </Animated.View>
    </view>
</template>

<script>
import { Animated, Easing } from 'react-native'

export default {
    components: {
        Animated
    },
    data: function() {
        return {
            animateOpacity: new Animated.Value(0)
        };
    },
    methods: {
        animateIn() {
            Animated.timing( 
                this.animateOpacity,
                {
                toValue: 1,
                easing: Easing.easeInOut,
                duration: 1200,
                }
            ).start();     
        }
    },
    mounted () {
        this.animateIn()
    }
};
</script>

got error:

Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.

Check the render method of ReactVueComponent.

Do I miss something ?

@Magnai1030
Copy link
Author

Magnai1030 commented Mar 19, 2019

@SaraTV9 I think you have to avoid to use animate in a template
just detach like:

import React from 'react';
import {  Animated, Easing,Text,View } from "react-native";
export class AnimatedOpacity extends React.Component {
    render() {
        return (
           <Animated.View class="container" :style="{opacity: this.props.animateOpacity}">
            <Text >MyComponent</Text>
            <Text >Test for animate a group</Text>
        </Animated.View>
        )
    }
}

and use like

<template>
    <view :style="{ flex: 1, backgroundColor: 'black'}">
        <animated-opacity :animateOpacity="animateOpacity"/>
    </view>
</template>

<script>
import { Animated, Easing } from 'react-native'
import {AnimatedOpacity} from ./AnimatedOpacity

export default {
    components: {
        AnimateOpacity
    },
    data: function() {
        return {
            animateOpacity: new Animated.Value(0)
        };
    },
    methods: {
        animateIn() {
            Animated.timing( 
                this.animateOpacity,
                {
                toValue: 1,
                easing: Easing.easeInOut,
                duration: 1200,
                }
            ).start();     
        }
    },
    mounted () {
        this.animateIn()
    }
};
</script>

i hope it will work

@giann
Copy link

giann commented Jun 3, 2019

Same issue here

@ashley00101010
Copy link

Same issue

@ashley00101010
Copy link

Anyone solved this issue?

@SaraTV9
Copy link

SaraTV9 commented Jul 17, 2019

@VanLaerAshley I used a trick. It seems that vus-native Animated does not work on nested elements. You need to animate every single item. It is long and painful but it works for most of the case!

Code does not work:

import React from 'react';
import {  Animated, Easing,Text,View } from "react-native";
export class AnimatedOpacity extends React.Component {
    render() {
        return (
           <Animated.View class="container" :style="{opacity: this.props.animateOpacity}">
            <Text >MyComponent</Text>
            <Text >Test for animate a group</Text>
        </Animated.View>
        )
    }
}

Change it like this and will work:

import React from 'react';
import {  Animated, Easing,Text,View } from "react-native";
export class AnimatedOpacity extends React.Component {
    render() {
        return (
           <view class="container">
            <Animated.Text  :style="{opacity: this.props.animateOpacity}">MyComponent</Animated.Text>
            <Animated.Text  :style="{opacity: this.props.animateOpacity}">Test for animate a group</Animated.Text>
        </view>
        )
    }
}

Not good practice and sometimes needs adjustments, but worked for me.

@icarter09
Copy link

@Magnai1030 can this issue be closed? After reading over the comments, sounds like you found a work-around/solution. Is that correct?

@ashley00101010
Copy link

ashley00101010 commented Dec 17, 2019

@icarter09 No, the workaround doesn't work in my case. The app keeps crashing with error code: "Maximum call stack size exceeded".

This is my code for opening a tabbed menu:

<template>
  <animated:View
    :scrollEnabled="false"
    :style="{
        height: growth,
        position:'absolute',
        bottom:0,
        tintColor: 'transparent',
        borderWidth: 0,
        width: '100%',
        zIndex:999,
        backgroundColor: '#F2F2F2',
        borderColor: 'transparent',
        borderWidth: 0,
        borderTopLeftRadius: 25,
        borderTopRightRadius: 25,
        }"
  >
    <nb-footer-tab
      horizontal="true"
      :style="{ position:'absolute', top: 15, backgroundColor:'transparent' }"
    >
      <TabMenuItem
        class="menuitem"
        v-for="item in $store.getters.menu1"
        :item="item"
        :key="item.text"
        :menu="handleButtonPress"
        :toggle="toggle"
        :route="$store.getters.route"
      />
    </nb-footer-tab>

    <nb-footer-tab :style="{ position:'absolute', top: 90, backgroundColor:'transparent'}">
      <TabMenuItem
        class="menuitem"
        v-for="item in  $store.getters.menu2"
        :item="item"
        :key="item.route"
        :menu="handleButtonPress"
        :toggle="toggle"
        :route="$store.getters.route"
      />
    </nb-footer-tab>

  </animated:View>
</template>

@kurtaschliman
Copy link

This seems to also occur in an Expo app in Production mode when using v-if in nested statements. Here's my template:

  <nb-container class="container">
    <status-bar :hidden="true" />
    <camera class="camera" ref="camera" :type="this.type">
      <image class="silhouette" v-if="!recording && !showCountdown" transparent :source="require('../static/images/silhouette.png')"/>
      <view v-if="showCountdown" class="countdownNumberContainer" >
        <text class="countdownNumber">{{countdownNumber}}</text>
      </view
    </camera>
      <view class="record-button-container">
      <nb-button v-if="!recording" rounded transparent :on-press="clickedStartButton" width="50" height="50" >
        <image :source="require('../static/images/camera_button.png')" />
      </nb-button>
      <nb-button v-if="recording" rounded transparent :on-press="clickedStopButton">
        <image :source="require('../static/images/stopbutton.png')" />
      </nb-button>
      </view>
  </nb-container>
</template>

When pressing the record button, the app crashes with RangeError: Maximum call stack size exceeded.

package.json:

{
  "main": "node_modules/expo/AppEntry.js",
  "scripts": {
    "start": "expo start",
    "android": "expo start --android",
    "ios": "expo start --ios",
    "web": "expo start --web",
    "eject": "expo eject"
  },
  "dependencies": {
    "@expo/vector-icons": "^10.0.6",
    "Base64": "^1.1.0",
    "aws-sdk": "^2.589.0",
    "axios": "^0.19.0",
    "base-64": "^0.1.0",
    "expo": "~36.0.0",
    "expo-av": "~8.0.0",
    "expo-background-fetch": "~8.0.0",
    "expo-camera": "^8.0.0",
    "expo-file-system": "~8.0.0",
    "expo-font": "~8.0.0",
    "expo-image-picker": "~8.0.0",
    "expo-linear-gradient": "~8.0.0",
    "expo-media-library": "~8.0.0",
    "expo-permissions": "^8.0.0",
    "expo-task-manager": "~8.0.0",
    "media-library": "^1.2.4",
    "native-base": "^2.13.8",
    "react": "~16.9.0",
    "react-dom": "~16.9.0",
    "react-native": "https://github.com/expo/react-native/archive/sdk-36.0.0.tar.gz",
    "react-native-gesture-handler": "^1.5.2",
    "react-native-paper": "^3.3.0",
    "react-native-reanimated": "^1.4.0",
    "react-native-vector-icons": "^6.6.0",
    "react-native-web": "~0.11.7",
    "vue-native-core": "0.1.4",
    "vue-native-helper": "0.1.4",
    "vue-native-router": "^0.1.1",
    "vuelidate": "^0.7.4",
    "vuex": "^3.1.2"
  },
  "devDependencies": {
    "@babel/core": "7.7.5",
    "babel-preset-expo": "~8.0.0",
    "vue-native-scripts": "0.1.4"
  },
  "private": true
}

@emaadali
Copy link

This issue seems to go away when binding the Animated _value directly. For example, lets say you have this component:

<template>
  <animated:view :style="{opacity: animatedOpacityValue}">
    <button @press="dim" title="Press Me" />
  </animated:view>
</template>

<script>
  import {Animated, Easing} from "react-native";

  export default {
    data() {
      return {
        animatedOpacityValue: new Animated.Value(1)
      };
    },
    methods: {
      dim() {
        Animated.timing(this.animatedOpacityValue, {
          toValue: 0,
          duration: 300,
          easing: Easing.in(),
        }).start();
      }
    },
  };
</script>

To resolve the "Maximum call stack size exceeded" error, you would change :style="{opacity: animatedOpacityValue}" to :style="{opacity: animatedOpacityValue._value}":

<template>
  <animated:view :style="{opacity: animatedOpacityValue._value}">
    <button @press="dim" title="Press Me" />
  </animated:view>
</template>

<script>
  import {Animated, Easing} from "react-native";

  export default {
    data() {
      return {
        animatedOpacityValue: new Animated.Value(1)
      };
    },
    methods: {
      dim() {
        Animated.timing(this.animatedOpacityValue, {
          toValue: 0,
          duration: 300,
          easing: Easing.in(),
        }).start();
      }
    },
  };
</script>

I don't know if this has any impact on performance.

@arjorie
Copy link

arjorie commented Jan 19, 2020

@Magnai1030 and how do you do that ?

My vue-native code:

<template>
    <view :style="{ flex: 1, backgroundColor: 'black'}">
        <animated:view class="container" :style="{opacity: animateOpacity}">
            <text class="title">MyComponent</text>
            <text class="text">Test for animate a group</text>
        </animated:view>
    </view>
</template>

<script>
import { Animated, Easing } from 'react-native'

export default {
    data: function() {
        return {
            animateOpacity: new Animated.Value(0)
        };
    },
    methods: {
        animateIn() {
            Animated.timing( 
                this.animateOpacity,
                {
                toValue: 1,
                easing: Easing.easeInOut,
                duration: 1200,
                }
            ).start();     
        }
    },
    mounted () {
        this.animateIn()
    }
};
</script>

Try to pass React Native component directly:

<template>
    <view :style="{ flex: 1, backgroundColor: 'black'}">
        <Animated.View class="container" :style="{opacity: animateOpacity}">
            <text class="title">MyComponent</text>
            <text class="text">Test for animate a group</text>
        </Animated.View>
    </view>
</template>

<script>
import { Animated, Easing } from 'react-native'

export default {
    components: {
        Animated
    },
    data: function() {
        return {
            animateOpacity: new Animated.Value(0)
        };
    },
    methods: {
        animateIn() {
            Animated.timing( 
                this.animateOpacity,
                {
                toValue: 1,
                easing: Easing.easeInOut,
                duration: 1200,
                }
            ).start();     
        }
    },
    mounted () {
        this.animateIn()
    }
};
</script>

got error:

Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
Check the render method of ReactVueComponent.

Do I miss something ?

Animated.View is not suported with vue native, Ive encountered the same issue by using dot properties but since using vue dot properties should be translated as animated:view

Anyways, I am encountering same issue but with my own button component. In dev, its working fine, but in prod, it says Maximum call stack exceeded as well.

Since Im using Button keyword which is already exist in vue native, does that an issue in using component names?

@martinnilson
Copy link

I don't know if this solves anyone else's problem but for me the simplest way to solve this was to abandon animated:view and instead animate an ordinary view element with javascript.

Example animates a popup from the bottom of the screen in 20 steps; initiated with this.animateGrowth([desired height], 20)

<view :style="{flex:1}"> ... </view>
<view :style="{height: popup_height}"> ... </view>
animateGrowth(height, step) {
        if(step > 5){
            this.popup_height = height/20*(20-step)
            step--
            setTimeout(() => this.animateGrowth(height, step), 10);
        } else if (step > 0) {
            this.popup_height = height/20*(20-step)
            step--
            setTimeout(() => this.animateGrowth(height, step), 30);
        }
},

@konglie
Copy link

konglie commented May 21, 2020

Hello, I also have this problem.

in my case, i fixed it with

Original code, on production will cause Maximum call stack size exceeded (android and iOS)

<template>
	...the animated view
</template>
<script>
import {Animated} from 'react-native';

export default {
	// ...
	computed: {
		animatedStyle(){
			return {opacity: this.myAnimatedValue.interpolate(...)}
		}
	},
	data(){
		return {
			// ...
			myAnimatedValue: new Animated.Value(0) <-- this is the problem
		}
	}
}
</script>

the FIX, is to remove myAnimatedValue from Vue instance, as follows

<script>
import {Animated} from 'react-native';
const myAnimatedValue = new Animated.Value(0); <-- MOVE IT here

export default {
	// ...
	computed: {
		animatedStyle(){
			// access the animated instance from outside of "this"
			return {opacity: myAnimatedValue.interpolate(...)}
		}
	},
	data(){
		return {
			// ...
			// myAnimatedValue: new Animated.Value(0) <-- this is the problem, delete this
		}
	}
}
</script>

in my case, it solved.

@bmbmjmdm
Copy link

Same problem

@bmbmjmdm
Copy link

@emaadali this worked for me, ilu

@SunPuzzle
Copy link

thanks @konglie its work solution
create animated value outside class, and use computed value for style

>>> ShakeHorizontalAnimation.vue

<template>
<animated:view :style="shakeAnimationStyle">
    <slot></slot>
</animated:view>
</template>

<script>
    import {Animated, Easing} from 'react-native';
    const shakeAnimation = new Animated.Value(0);

    export default {
        computed:{
            shakeAnimationStyle()
            {
                return {
                    transform: [{translateX: shakeAnimation}]
                };
            }
        },
        methods: {
            animate() {
                shakeAnimation.setValue(0);
                Animated.sequence([
                    Animated.timing(shakeAnimation, {toValue: 10, duration: 100, useNativeDriver: true}),
                    Animated.timing(shakeAnimation, {toValue: -10, duration: 100, useNativeDriver: true}),
                    Animated.timing(shakeAnimation, {toValue: 10, duration: 100, useNativeDriver: true}),
                    Animated.timing(shakeAnimation, {toValue: 0, duration: 100, useNativeDriver: true})
                ]).start();
            },
        },
    }
</script>

@RishabhKarnad
Copy link
Contributor

In general, animated values should not be placed in data or computed, which are reactive. The solution suggested by @konglie may work, but to ensure that a unique animated value is used for each instance of the component, the value should be added to the $options of the component.

<template>
    <animated:view :style="{ left: $options.left }">
        ...
    </animated:view>
    <animated:view :style="{ left: $options.interpolatedLeft }"
        ...
    </animated:view>
</template>

<script>
export default {
    left: new Animated.Value(0),
    created() {
        this.$options.interpolatedLeft = this.$options.left.interpolate({ ... })
    },
    mounted() {
        this.$options.left.timing({ ... }).start()
    },
}
</script>

$options can be used to keep component properties this way that are not supposed to be reactive. Since Animated.Values are themselves stateful, they should not be kept in data to avoid unnecessary rerenders and difficult to debug issues.

@RishabhKarnad
Copy link
Contributor

Closing this issue. Please reopen if you think this is still an issue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests