我有一个页面,其中包含不同的组件,其中一个组件中具有循环动画,我将在安装子组件时启动动画。当我切换到另一个屏幕时,我想停止动画。因此,我尝试停止在componentWillUnmount生命周期中包含一个组件的动画,该动画将运行我的stop函数,但是此后,它将再次运行动画,并且我不知道如何停止它。
实际上,我想确保内存安全,我希望动画仅在安装此组件时开始,而在卸载时停止。
这是我的第一个包含动画子组件(StoreBoxItems)的组件:
export class StoreBoxPackages extends Component {
render() {
const {
onPress,
packTitle,
currency,
discount,
items,
price,
packageType,
keyIndex,
packID,
} = this.props;
//let b = [];
let rows = []
let itemsNumber = 0;
if (items != null){
//console.log('ssssxxxx')
itemsNumber = items.length;
}
//console.log('itemsNumber', itemsNumber)
let rowsNumber = Math.ceil(itemsNumber/3);
//console.log('rowNum' , rowsNumber)
let boxIndex = 0;
for(let i = 1; i <= rowsNumber; i++){
let row = [];
for(let j = 0; j< 3 && boxIndex<itemsNumber; j++,boxIndex++){
row.push(
<StoreBoxItems
stateKey={`${i}${j}`}
price={price}
currency={currency}
unit={items[boxIndex].unit}
type={items[boxIndex].type}
titleColor={items[boxIndex].caption_color}
duration={items[boxIndex].duration}
ientifier={items[boxIndex].identifier}
asset_id={items[boxIndex].asset_id}
packageType={packageType}
caption={items[boxIndex].caption}
itemID={packID}
onPress={onPress}
/>
)
if(boxIndex + 1 == itemsNumber && itemsNumber > 3){
let reminder = itemsNumber % 3;
let moreBox = 3 - reminder;
//console.log('boxIndex', boxIndex ,'itemsNumber', itemsNumber, 'reminder', reminder , 'moreBox', moreBox)
if(reminder != 0 && moreBox > 0){
for(let k=0;k<moreBox;k++){
row.push(<View style={{flex : 1}}></View>)
}
}
}
}
rows.push(
<View key={makeid(8)} style={{flexDirection: 'row', flexGrow: 1, alignItems: 'center', justifyContent: 'space-around' }}>
{row}
</View>
)
}
return (
<View key={makeid(8)} style={{flexGrow: 1}}>
{rows}
<View>
{packageType == 'COLLECTION' ?
<StoreBoxItemsBtn
price={price}
currency={currency}
itemID={packID}
onPress={onPress}
/>
: null }
</View>
</View>
);
}
}
这是我的孩子动画组件(StoreBoxItems)
export class StoreBoxItems extends Component {
constructor(props) {
super(props);
this.state = {
progress: new Animated.Value(0),
appState: AppState.currentState
};
this.backColor = '#201F3F';
this.runAnimationSate = true;
}
componentWillMount(){
//this._chackBackColor()
this.runAnimation();
}
componentDidMount() {
AppState.addEventListener("change", this._handleAppStateChange);
}
componentWillUnmount(){
AppState.removeEventListener("change", this._handleAppStateChange);
console.log('unmonted anime');
this.runAnimationSate = false;
Animated.timing(this.state.progress).stop();
//Animated.loop(Animated.timing(this.state.progress)).stop();
}
runAnimation() {
console.log('run animation');
this.state.progress.setValue(0);
Animated.timing(this.state.progress, {
toValue: 1,
duration: 3000,
easing: Easing.linear,
useNativeDriver : true
})
.start(() => {
if (this.runAnimationSate) {
this.runAnimation();
}
})
}
_handleAppStateChange = (nextAppState) => {
if (this.state.appState.match(/inactive|background/) && nextAppState === "active"){
console.log('active')
this.runAnimation();
}else{
console.log('DEactive')
Animated.timing(this.state.progress).stop();
this.setState({appState: nextAppState});
}
}
render() {
const {
stateKey,
price,
currency,
caption,
unit,
type,
duration,
ientifier,
asset_id,
titleColor,
packageType,
itemID,
onPress
} = this.props;
let itemHeader = '';
let xduration = 0;
switch (type) {
case "BOOSTER" :
xduration = (duration / 3600);
if(xduration >= 1){
itemHeader = `${xduration} H, ${ientifier}x`;
}else{
xduration = (duration / 60);
itemHeader = `${xduration} Min, ${ientifier}x`;
}
break;
case "COIN" :
itemHeader = unit;
break;
default :
itemHeader = unit;
break;
}
return (
<View key={makeid(8)} style={[styles.boxItems]}>
<View style={[styles.boxItemIconHolder,{backgroundColor : this.backColor}]}>
<Text style={[{color : titleColor}, globalStyles.mediumFont, globalStyles.acmeFont]}>{itemHeader}</Text>
<Image
source={icons[asset_id]}
style={{ width: normalize(40), height: normalize(40), marginTop: 2 }}
/>
{type == "COIN" ?
<LottieView
style={{
position: 'absolute',
height: 30,
width: 30,
zIndex:1
}}
progress={this.state.progress}
source={lotties['shineBox']}
loop={true}
//autoPlay={true}
/>
: null }
</View>
<Text style={[globalStyles.lightColor, globalStyles.mediumFont, globalStyles.acmeFont, styles.boxItemTitle]}>{caption}</Text>
{packageType == 'ITEM' ?
<StoreBoxItemsBtn
price={price}
currency={currency}
itemID={itemID}
onPress={onPress}
/>
: null }
</View>
);
}
}
答案 0 :(得分:1)
这很奇怪,因为您似乎已经正确执行了,是否尝试过this.state.progress.stopAnimation()?
此外,我的建议是do not put animated value into state
状态值在React和React Native中用于动态更新 一个组件。这意味着该组件的render()方法是 每次状态更新时调用。
现在您可能会认为,由于组件已更新 动态地,可以将动画值存储在状态中。
假设我们已将动画滚动事件映射到状态。依此类推 每次滚动时,都会调用render方法,从而导致 不必要的开销。因此,如果我们在屏幕上滚动700像素, 方法已更新700次。
答案 1 :(得分:0)
那是因为我正在使用reactnavigation,发现我需要使用它的lifeCycle而不是react componentWillUnmount。 在我的情况下,我为willBlur状态及其运行状况添加了一个监听器,
https://reactnavigation.org/docs/en/navigation-lifecycle.html