React Native fetch перед отрисовкой компонентов - PullRequest
1 голос
/ 26 мая 2020

Я создаю приложение Reat Native, которое подключается к API, из которого оно получает данные.

Я использую React Navigation для управления навигацией. В приложении есть навигатор стека и навигатор нижней вкладки. StackNavigator имеет 4 экрана:

  • SignupScreen, который обрабатывает создание учетной записи;
  • LoginScreen для ручного входа в систему;
  • SplashScreen, который проверяет для локального токена и автоматически входит в систему пользователя;
  • A LoadingScreen, который запускает вызов начальной выборки API, сохраняет ответ в состоянии и переходит на экран MainFlow;
  • Экран MainFlow, содержащий TabNavigator.

TabNavigator имеет два экрана: FeedScreen, Account и More, где начальным экраном является FeedScreen.

Все потоки регистрации / входа в систему / локальные работают нормально.

Проблема : после успешного входа пользователя в систему LoadingScreen запускается вызов API, но MainFlow компонентов отрисовываются до того, как данные будут в состоянии. Поскольку компоненты в MainFlow нуждаются в данных, возникает ошибка. Как я могу визуализировать компоненты FeedScreen только после того, как там есть данные?

В LoadingScreen я инициирую вызов API для useEffect из объекта контекста, 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 - это функция в 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?

Ответы [ 2 ]

1 голос
/ 26 мая 2020

Для меня я буду использовать экран вместо двух экранов следующим образом:

 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;
0 голосов
/ 28 мая 2020

Почему бы вам не установить начальное состояние вашего контекста на 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;
...