如何等待React Native自定义Hook返回确定值后再执行逻辑?
React Native自定义Hook异步状态等待问题解决
问题概述
我编写了一个自定义React Native Hook useHasSubscription,用于返回用户的订阅状态(true/false)。但在AppLoaded组件中调用时,Hook初始返回null,导致默认渲染SubscriptionScreen,直到内部异步逻辑完成才更新状态,打乱了应用流程。尝试将Hook改为async后出现大量错误,需要解决该问题。
原代码
自定义Hook useHasSubscription
export const useHasSubscription = () => { const [appState, setAppState] = useState(AppState.currentState); const [subscribed, setSubscribed] = useState(null) const [isLoading, setLoading] = useState(true) const { connected, subscriptions, getSubscriptions, } = useIAP(); useEffect(() => { console.log("Connected? ", connected, "App State: ", appState) if (!connected) { console.log('not connected') return; } if (appState === "active") { console.log('app is active, checking status') getSubscriptions({ skus: ["sku"] }).then(()=>{ return IapIosSk2.subscriptionStatus("sku") }).then((res) => { console.log("subscription Status: ", res); const temp = res.some(({state})=> ( state === 'subscribed' || state === 'inGracePeriod' )); setSubscribed(temp); }) .catch((err) => { //test here with error/no internet console.log("failed to get status: ", err); }); } setLoading(false) }, [ connected, appState, getSubscriptions, subscribed, isLoading]); return subscribed };
AppLoaded 组件
const AppLoaded = () => { const isSubscribed = useHasSubscription(); // 等待其返回false或true,而非null console.log("is Subbed? " + isSubscribed); return ( <PaperProvider theme={theme}> <SafeAreaProvider> {isSubscribed ? ( <NavigationRoot /> ) : ( <SubscriptionScreen /> )} </SafeAreaProvider> </PaperProvider> ); };
解决方案
1. 修改Hook,返回加载状态和订阅状态
React Hook不能是异步函数,但可以在内部用async/await处理异步逻辑,同时返回加载状态和订阅状态,让组件能判断是否需要等待。同时修正useEffect的依赖数组(移除subscribed和isLoading,避免无限循环):
export const useHasSubscription = () => { const [appState, setAppState] = useState(AppState.currentState); const [subscribed, setSubscribed] = useState(null) const [isLoading, setLoading] = useState(true) const { connected, getSubscriptions, } = useIAP(); useEffect(() => { const checkSubscriptionStatus = async () => { console.log("Connected? ", connected, "App State: ", appState) if (!connected) { console.log('not connected') // 未连接时设置默认订阅状态为false setSubscribed(false); setLoading(false); return; } if (appState !== "active") { setLoading(false); return; } try { console.log('app is active, checking status') await getSubscriptions({ skus: ["sku"] }); const res = await IapIosSk2.subscriptionStatus("sku"); console.log("subscription Status: ", res); const isSubscribed = res.some(({state})=> state === 'subscribed' || state === 'inGracePeriod' ); setSubscribed(isSubscribed); } catch (err) { console.log("failed to get status: ", err); // 出错时设置默认订阅状态为false setSubscribed(false); } finally { setLoading(false); } }; checkSubscriptionStatus(); }, [connected, appState, getSubscriptions]); return { subscribed, isLoading }; };
2. 在组件中根据加载状态等待
修改AppLoaded组件,先判断加载状态,显示加载界面直到获取到确定的订阅状态:
import { ActivityIndicator, View } from 'react-native'; const AppLoaded = () => { const { subscribed, isLoading } = useHasSubscription(); // 加载中时显示加载组件 if (isLoading) { return ( <PaperProvider theme={theme}> <SafeAreaProvider> <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}> <ActivityIndicator size="large" color="#0000ff" /> </View> </SafeAreaProvider> </PaperProvider> ); } // 此时subscribed已有确定值(true/false) return ( <PaperProvider theme={theme}> <SafeAreaProvider> {subscribed ? <NavigationRoot /> : <SubscriptionScreen />} </SafeAreaProvider> </PaperProvider> ); };
关键说明
- React Hook不能定义为
async函数,因为Hook必须同步执行才能保证调用顺序的一致性,违反此规则会直接报错。 - 通过在Hook内部封装异步逻辑,并返回加载状态,组件可以优雅处理等待过程,避免初始
null值导致的错误渲染。 - 错误场景下主动设置
subscribed为默认值(如false),确保组件始终能拿到确定的状态值。
内容的提问来源于stack exchange,提问作者guitarman0456
相关产品推荐
相关产品推荐

