我想在React Native中启动应用程序时运行功能(调用函数)。
当应用程序启动时,有启动屏幕(默认),它加载应用程序几秒钟,然后读取index.js
根文件来渲染应用程序。
我找不到一种方法来运行我自己的功能在这个应用程序的加载状态,只要我的功能不能解决显示React Native的闪屏。
有什么解决方案/想法吗?
下面的代码应该满足任何想要创建动画启动屏幕的人的需求,或者在启动屏幕期间启动一些加载过程。
基本版本不需要任何额外的软件包,但是,它假设您正在使用React Navigation 5.x
,或用于基于屏幕的导航的类似解决方案。
我在评论中为那些希望使用expo-splash-screen
(或类似的包)的人留下了代码。它被用来确保静态闪屏保持可见,直到整个应用程序树完成初始渲染——否则,当静态闪屏被隐藏时,会出现短暂的闪烁,但到那时应用程序树还没有完成安装。
import React from "react";
import { Animated, StyleSheet, View } from "react-native";
import { createStackNavigator } from "@react-navigation/stack";
// import * as SplashScreen from "expo-splash-screen";
/*
Call this function here such that the static splash remains visible
before rendering any component in the App tree.
*/
// SplashScreen.preventAutoHideAsync().catch((error) => {
// // While developing, this function will be called multiple times,
// // at times when the static splash screen is already hidden.
// // Thus, it will reject with an error.
// // You can safely ignore that error and move on with real business.
// // console.warn("SplashScreen.preventAutoHideAsync error:", error);
// });
const { Navigator, Screen } = createStackNavigator();
export default class App extends React.PureComponent {
render = () => {
return <Navigator initialRouteName="Splash">
<Screen name="Splash" component={SplashScreen} />
<Screen name="HelloWorld" component={HelloWorldScreen} />
</Navigator>;
}
}
class SplashScreen extends React.PureComponent {
state = { currentProgress: 0 };
progress = new Animated.Value(0);
progressStyle = [
styles.progressBar,
{ width: this.progress.interpolate(PROGRESS_INTERPOLATION) }
];
setStateAsync = setStateAsync.bind(this);
animateProgressBar = (toValue = 0) => {
Animated.timing(this.progress, {
toValue,
duration: ANIMATION_DURATION,
isInteraction: false,
useNativeDriver: false // Layout props are not supported by Animated module
}).start();
}
componentDidMount = () => {
// If you're using Expo SplashScreen, uncomment the code below
// to hide the static splash screen.
// SplashScreen.hideAsync().catch((error) => {
// // While developing, this function will be called multiple times,
// // at times when the static splash screen is already hidden.
// // Thus, it will reject with an error.
// // You can safely ignore that error and move on with real business.
//
// // console.warn("SplashScreen.hideAsync error:", error);
// });
// Start your loading procedure here
this.doSomething()
.then(() => { return this.setStateAsync({ currentProgress: 15 }); })
.then(() => { return this.doSomething(); })
.then(() => { return this.setStateAsync({ currentProgress: 35 }); })
.then(() => { return this.doSomething(); })
.then(() => { return this.setStateAsync({ currentProgress: 70 }); })
.then(() => { return this.doSomething(); })
.then(() => { return this.setStateAsync({ currentProgress: 100 }); })
// Allow the progress bar to visibly animate to 100%
.then(() => { return setTimeoutAsync(ANIMATION_DURATION + EXTRA_DELAY_TO_100_PERCENT); })
// Once all loading tasks are finished, navigate to your next screen
.then(() => { this.props.navigation.navigate("HelloWorld"); })
// Make sure the following never occurs in production
.catch((startupError) => { console.error("An error occurred during startup", startupError); });
}
componentDidUpdate = (prevProps, prevState) => {
const { currentProgress } = this.state;
if (currentProgress !== prevState.currentProgress) {
// Passively react to currentProgress changes
// and animate the progress bar accordingly
this.animateProgressBar(currentProgress);
}
}
render = () => {
return <View style={styles.container}>
<View style={styles.progressContainer}>
<Animated.View style={this.progressStyle} />
</View>
</View>;
}
}
class HelloWorldScreen extends React.PureComponent {
render = () => { return <Text>Hello, world!</Text>; }
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
paddingHorizontal: 50
},
progressContainer: {
width: "100%",
height: 10
},
progressBar: {
// width set by animation
height: "100%",
backgroundColor: "#000",
borderRadius: 5,
overflow: "hidden"
}
});
const PROGRESS_INTERPOLATION = {
inputRange: [0, 100],
outputRange: ["0%", "100%"],
// if the input is outside the range 0-100, clamps the output to specified outputRange values
extrapolate: "clamp"
};
const ANIMATION_DURATION = 200; // milliseconds
const EXTRA_DELAY_TO_100_PERCENT = 50; // milliseconds
/*
Helper functions that allow to easily work with async functions
*/
// Promisify React.Component's setState method
// Remember to .bind(this) in the class you use it
function setStateAsync(state = {}) {
return new Promise((resolve, reject) => {
try { this.setState(state, resolve); }
catch (error) { reject(error); }
});
}
// Promisify setTimeout
function setTimeoutAsync(timeout = 1000){
return new Promise((resolve, reject) => {
try { setTimeout(resolve, timeout); }
catch (error) { reject(error); }
})
}
// Dummy method that simulates some loading delay, 0-1000 milliseconds
function doSomething() { return setTimeoutAsync(Math.random() * 1000); }