I am creating a Reat Native app which connects to an API from which it gets data.
I am using React Navigation to handle navigation. The app has a Stack Navigator and a Bottom Tab Navigator. The StackNavigator
has 4 screens:
SignupScreen
which handles creating account;LoginScreen
for handlong log in;SplashScreen
that checks for a local token and logs in the user automatically;- A
LoadingScreen
that triggers the initial fetch call to the API, stores the response in state and navigates to theMainFlow
screen; - A
MainFlow
screen that contains theTabNavigator
.
The TabNavigator
has two screens, FeedScreen
, Account
and More
where the initial screen is FeedScreen
.
The signup/login/local flows are all working fine.
The issue: Once the user is logged in successfully the LoadingScreen is triggering the API call but the MainFlow
components are being rendered before the data is in state. Because the components in MainFlow
need the data, an error is thrown. How can I render the FeedScreen
components only once the data is there?
In the LoadingScreen
I am triggering an API call on useEffect
from a context object, QuestionContext
:
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
is a function in QuestionContext
which makes the API call and navigates to 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
is working fine: the API call is successful and I can see that the response is stored in state. However, it navigates to MainFlow
before that happens.
Finally, this is the 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;
The FeedScreen
renders a QuestionCard
which needs the data in questionState
. This is what throwing the error: the QuestionCard
is being rendered before the data is in state.
How can I make the navigation only navigate to FeedScreen
once the necessary data is in state? Or alternatively, render something else than the QuestionCard
while the data is not there and once the data is in questionState
render the QuestionCard
?