我正在创建一个Reat Native应用程序,该应用程序连接到API并从中获取数据。
我正在使用React Navigation来处理导航。该应用程序具有堆栈导航器和底部选项卡导航器。 StackNavigator
有4个屏幕:
SignupScreen
,负责创建帐户; LoginScreen
进行手工登录; SplashScreen
,用于检查本地令牌并自动登录用户; LoadingScreen
,它会触发对API的初始提取调用,将响应存储在状态中,并导航到MainFlow
屏幕; MainFlow
屏幕,其中包含TabNavigator
。 TabNavigator
有两个屏幕,FeedScreen
,Account
和More
,其中初始屏幕为FeedScreen
。
注册/登录/本地流均正常运行。
问题:用户成功登录后,LoadingScreen会触发API调用,但是在数据处于状态之前会呈现MainFlow
组件。由于MainFlow
中的组件需要数据,因此会引发错误。仅在数据存在后,才如何渲染FeedScreen
组件?
在LoadingScreen
中,我从上下文对象useEffect
触发了QuestionContext
的API调用:
const LoadingScreen = ({ navigation }) => {
const [loading, setLoading] = useState(true);
const { state: authState } = useContext(AuthContext);
const { getQuestionsForUser, getAllQuestions } = useContext(QuestionContext);
useEffect(() => {
getAllQuestions();
}, []);
return (
<View style={styles.container}>
<YonStatusBar backgroundColor="#310B3B" />
<Image source={splashLogo} containerStyle={styles.splashLogo} />
<ActivityIndicator />
</View>
);
};
export default LoadingScreen;
getAllQuestions
是QuestionContext
中的一个函数,该函数进行API调用并导航到FeedScreen
:
const getAllQuestions = (dispatch) => {
return async () => {
try {
const token = await AsyncStorage.getItem('token');
const config = { headers: { Authorization: `Bearer ${token}` } };
const response = await yonyonApi.get(`/questions`, config);
dispatch({ type: 'GET_ALL_QUESTIONS', payload: response.data });
RootNavigation.navigate('MainFlow');
} catch (e) {
console.log(e);
}
};
};
getAllQuestions
工作正常:API调用成功,并且可以看到响应存储在状态中。但是,它会在发生这种情况之前导航到MainFlow
。
最后,这是FeedScreen
:
const FeedScreen = () => {
const { state: questionState } = useContext(QuestionContext);
return (
<ScrollView style={styles.container}>
{console.log(questionState.questions)}
<View style={styles.listContainer}>
<QuestionCard />
</View>
</ScrollView>
);
};
export default FeedScreen;
FeedScreen
呈现了一个QuestionCard
,它需要questionState
中的数据。这就是引发错误的原因:QuestionCard
是在数据处于状态之前呈现的。
一旦必要的数据处于状态,如何使导航仅导航到FeedScreen
?或者,在数据不存在的情况下渲染QuestionCard
之外的其他内容,一旦数据在questionState
中,则渲染QuestionCard
?
答案 0 :(得分:2)
对我来说,我将使用屏幕而不是两个屏幕,如下所示:
const FeedScreen = () => {
const [loading, setLoading] = useState(true);
const { state: authState } = useContext(AuthContext);
const [data, setData] = useState([]);
const getAllQuestions = (dispatch) => {
return async () => {
try {
const token = await AsyncStorage.getItem('token');
const config = { headers: { Authorization: `Bearer ${token}` } };
const response = await yonyonApi.get(`/questions`, config);
setData(response.data)
setLoading(false)
} catch (e) {
console.log(e);
}
};
};
useEffect(() => {
getAllQuestions();
}, []);
return (
<ScrollView style={styles.container}>
{
(loading)?
<ActivityIndicator/>
:
<View style={styles.listContainer}>
<QuestionCard data={data}/>
</View>
}
</ScrollView>
);
};
export default FeedScreen;
答案 1 :(得分:0)
为什么不将上下文的初始状态设置为null
,如果不是null
,则渲染组件?
const [questionState, setQuestionState] = useState(null);
...
const FeedScreen = () => {
const { state: questionState } = useContext(QuestionContext);
return (
<ScrollView style={styles.container}>
{!!questionState?.questions && console.log(questionState.questions)}
<View style={styles.listContainer}>
<QuestionCard />
</View>
</ScrollView>
);
};
export default FeedScreen;