如果状态更改,动画将不会启动(用于演示的简短小吃)



小吃在这里

你好,我被一个愚蠢的问题卡住了,我快疯了。

我只是想在屏幕聚焦时(在选项卡栏导航中(制作一个简单优雅的动画。我的零食运行良好,直到我在屏幕中执行状态更改。然后动画就不会开始了,即使调用并执行了来自焦点侦听器的回调(检查日志(为什么

我做了一个按钮手动触发动画。。。它有效!????我想我已经把零食说清楚了,但如果你需要更多信息,请问我。我恳求你,请帮助一个绝望的兄弟。

小吃在这里

如果你懒得点击零食:

import React, { useState, useEffect } from "react";
import { Text, View, Animated, Dimensions, StyleSheet, SafeAreaView, Button } from 'react-native';
import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
function HomeScreen({navigation}) {
const initialXPos = Dimensions.get("window").height * 0.5 ;
const xPos = new Animated.Value(initialXPos);
const opacity = new Animated.Value(0);
const [change, setChange] = useState(true)
useEffect(() => {
const unsubscribe = navigation.addListener("focus", comingFromBot);
return unsubscribe;
}, []);
const comingFromBot = () => {
xPos.setValue(initialXPos);
opacity.setValue(0);
Animated.parallel([
Animated.spring(xPos, {
toValue: 100,
tension:3,
useNativeDriver: true,
}),
Animated.timing(opacity, {
toValue: 1,
duration: 1000,
useNativeDriver: true,
}),
]).start();
console.log("Animation's Fired!");
};
return (
<SafeAreaView style={{flex:1}}>
<Animated.View style={[
styles.container,
{ transform: [{ translateY: xPos }] },
{ opacity: opacity },
]}>
<Text style={{fontSize:30}}>{change ? "Home!" : "TIMMY!"}</Text>
</Animated.View>
{/* debug */}
<View style={styles.fire}>
<Button title="fire" onPress={() => comingFromBot()}/>
</View>
<View style={styles.change}>
<Button title="change" onPress={() => setChange(!change)}/>
</View>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: { flex: 1, alignItems: 'center' },
fire:{position:"absolute", width:"100%", bottom:0},
change:{position:"absolute", width:"100%", bottom:48}
});
function SettingsScreen() {
return (
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center', padding:8 }}>
<Text>{"Go to Home tab again, and notice the animation.nnEXCEPT if we changed the text... WHY?nnBUT still works if we fire the animation with the button, but after still won't work on focus detection... HOW?nnWorks if you hot reload / hard reload the app... HELP?"}</Text>
</View>
);
}
const Tab = createBottomTabNavigator();
function MyTabs() {
return (
<Tab.Navigator>
<Tab.Screen name="Home" component={HomeScreen} />
<Tab.Screen name="Settings" component={SettingsScreen} />
</Tab.Navigator>
);
}
export default function App() {
return (
<NavigationContainer>
<MyTabs />
</NavigationContainer>
);
}

它不起作用,因为您没有遵循钩子的规则。以下内容在您的代码中是错误的:

  1. useEffect钩子中使用外部变量,但传递空的依赖数组
  2. 动画值需要位于useStateuseRef挂钩中,这样就不会在每次渲染时重新创建它们

然后动画就不会开始了,即使调用并执行了来自焦点侦听器的回调(检查日志(。。。为什么?

问题是,回调是在重新渲染时的状态更新后重新创建的,因此传递给焦点侦听器的回调与渲染中的回调不再相同。由于您的动画值也不在state/ref中,所以在旧焦点侦听器引用旧值时,还会创建新的动画值。基本上,您看到的日志来自旧的侦听器,而不是新的侦听器。

你应该使用官方的esint插件,并确保你修复了它的所有警告/错误,这样就可以避免这样的问题。

要修复您的代码,请执行以下更改:

const [xPos] = React.useState(() => new Animated.Value(initialXPos));
const [opacity] = React.useState(() => new Animated.Value(0));
const [change, setChange] = useState(true)
useEffect(() => {
const unsubscribe = navigation.addListener("focus", comingFromBot);
return unsubscribe;
}, [navigation, comingFromBot]);
const comingFromBot = useCallback(() => {
xPos.setValue(initialXPos);
opacity.setValue(0);
Animated.parallel([
Animated.spring(xPos, {
toValue: 100,
tension:3,
useNativeDriver: true,
}),
Animated.timing(opacity, {
toValue: 1,
duration: 1000,
useNativeDriver: true,
}),
]).start();
console.log("Animation's Fired!");
}, [xPos, opacity]);

我基本上添加了useCallback,修复了依赖数组,并将动画值移动到useState挂钩。

多亏了@satya164:Sack ,我终于结束了

我也希望我以前在文件中读过这一点。

HomeScreen的代码:

// HomeScreen.js
function HomeScreen({navigation}) {
const initialXPos = Dimensions.get("window").height * 0.5 ;
const xPos = useRef(new Animated.Value(initialXPos)).current 
const opacity = useRef(new Animated.Value(0)).current 
const [change, setChange] = useState(true)
useEffect(() => {
const unsubscribe = navigation.addListener("focus", comingFromBot);
return unsubscribe;
}, [navigation, comingFromBot]);
const comingFromBot = useCallback(() => {
xPos.setValue(initialXPos);
opacity.setValue(0);
Animated.parallel([
Animated.spring(xPos, {
toValue: 100,
tension:3,
useNativeDriver: true,
}),
Animated.timing(opacity, {
toValue: 1,
duration: 1000,
useNativeDriver: true,
}),
]).start();
console.log("Animation's Fired!");
}, [xPos, opacity, initialXPos ]);
return (
<SafeAreaView style={{flex:1}}>
<Animated.View style={[
styles.container,
{ transform: [{ translateY: xPos }] },
{ opacity: opacity },
]}>
<Text style={{fontSize:30}}>{change ? "Home!" : "TIMMY!"}</Text>
</Animated.View>
{/* debug */}
<View style={styles.fire}>
<Button title="fire" onPress={() => comingFromBot()}/>
</View>
<View style={styles.change}>
<Button title="change" onPress={() => setChange(!change)}/>
</View>
</SafeAreaView>
);
}

相关内容

最新更新