Как мне отображать экраны в соответствии с переменными состояния?

#javascript #react-native

#javascript #react-native

Вопрос:

Обновить

Кто-то услужливо предложил объединить тройные операторы в ответах ниже, но я боюсь, что это не сработает. Я скопировал свою версию их решения ниже. Ошибка Error: A navigator cannot contain multiple 'Screen' components with the same name (found duplicate screen named 'Welcome')

 // This is the root stack navigator.
// It is currently the main skeleton of the navigation logic

const RootStack = createStackNavigator();

const RootStackScreen = () => {
  React.useEffect(() => {
    SplashScreen.hide();
  }, []);

  const [hasCompletedIntro, setHasCompletedIntro] = React.useState(false);
  const [hasSelectedLanguage, setHasSelectedLanguage] = React.useState(true);

  return (
    <RootStack.Navigator>
      {hasSelectedLanguage ? (
        <>
          <RootStack.Screen name="Welcome" component={WelcomeScreen} />
          <RootStack.Screen
            name="HowToUseThisApp"
            component={HowToUseThisAppScreen}
          />
          <RootStack.Screen name="Home" component={AppTabsScreen} />
        </>
      ) : (
        <RootStack.Screen
          name="Choose Your Language"
          component={ChooseYourLanguageScreen}
        />
      )}
      {!hasCompletedIntro amp;amp; hasSelectedLanguage ? (
        <>
          <RootStack.Screen name="Welcome" component={WelcomeScreen} />
          <RootStack.Screen
            name="HowToUseThisApp"
            component={HowToUseThisAppScreen}
          />
          <RootStack.Screen name="Home" component={AppTabsScreen} />
        </>
      ) : (
        <RootStack.Screen name="Home" component={AppTabsScreen} />
      )}
    </RootStack.Navigator>
  );
};
  

Наше приложение использует React Native 0.63.2 и React Navigation v5. Мы используем функциональные компоненты только с перехватами, без классов.

Мне нужно найти способ отображать следующие экраны в соответствии со следующими частями состояния, поэтому:

  • если значения hasSelectedLanguage И hasCompletedIntro равны true, они должны перейти на рабочий стол.

  • Значение hasSelectedLanguage равно true, но значение hasCompletedIntro равно false, они должны перейти на экран приветствия.

  • Значение выбранного языка равно false, они должны перейти на экран выбора языка.

Как вы можете видеть во фрагменте кода, я уже нашел способ отображать экраны в соответствии с логическим состоянием hasCompletedIntro , но React Navigation 5 выдает ошибки при попытке связать троичные операторы. Я застрял.

Я хотел бы знать, как отображать экраны с учетом приведенных выше маркеров, сохраняя при этом навигацию, связанную с hasCompletedIntro троичным элементом, который уже есть в коде.

 import 'react-native-gesture-handler';
import React from 'react';
import SplashScreen from 'react-native-splash-screen';
import AsyncStorage from '@react-native-community/async-storage';

import { NavigationContainer } from '@react-navigation/native';
import { createBottomTabNavigator } from '@react-navigation/bottom-tabs';
import { createStackNavigator } from '@react-navigation/stack';

import HomeScreen from '../screens/HomeScreen';
import WelcomeScreen from '../screens/WelcomeScreen';
import AppMenuScreen from '../screens/AppMenuScreen';
import HowToUseThisAppScreen from '../screens/HowToUseThisAppScreen';
import ChooseYourLanguageScreen from '../screens/ChooseYourLanguageScreen';

// This is the tab navigator for the bottom tabs containing the Home and More stack navigators

const AppTabs = createBottomTabNavigator();

const AppTabsScreen = () => {
  return (
    <AppTabs.Navigator
      AppTabsBarOptions={{
        labelStyle: {
          fontSize: 15,
          fontWeight: '600',
          marginBottom: 8,
        },
      }}>
      <AppTabs.Screen name="Home" component={HomeScreen} />
      <AppTabs.Screen name="App Menu" component={AppMenuScreen} />
    </AppTabs.Navigator>
  );
};

// This is the root stack navigator.
// It is currently the main skeleton of the navigation logic

const RootStack = createStackNavigator();

const RootStackScreen = () => {
  React.useEffect(() => {
    SplashScreen.hide();
  }, []);

  const [hasCompletedIntro, setHasCompletedIntro] = React.useState(false);
  const [hasSelectedLanguage, setHasSelectedLanguage] = React.useState(false);

  return (
    <RootStack.Navigator>
      {hasCompletedIntro ? (
        <RootStack.Screen name="Home" component={AppTabsScreen} />
      ) : (
        <>
          <RootStack.Screen
            name="Choose Your Language"
            component={ChooseYourLanguageScreen}
          />
          <RootStack.Screen name="Welcome" component={WelcomeScreen} />
          <RootStack.Screen
            name="HowToUseThisApp"
            component={HowToUseThisAppScreen}
          />
          <RootStack.Screen name="Home" component={AppTabsScreen} />
        </>
      )}
    </RootStack.Navigator>
  );
};

export default () => {
  return (
    <NavigationContainer>
      <RootStackScreen />
    </NavigationContainer>
  );
};
  

Комментарии:

1. » но React Navigation 5 выдает ошибки, когда я пытаюсь связать троичные операторы». Покажите код, который вы пробовали, и каковы ошибки.

2. @Code-Apprentice Я обновил сообщение с ошибкой. Спасибо!

3. Проблема с кодом из вашей правки заключается в том, что условия не являются взаимоисключающими, поэтому отображается более одного экрана приветствия. На самом деле, условия в вашем коде не соответствуют тому, что вы описываете в тексте вашего вопроса. Если вы выровняете их, то все будет работать так, как вы хотите.

4. Смотрите мой полностью обновленный ответ ниже.

Ответ №1:

Есть две потенциальные проблемы с вашей попыткой связать троичные операторы:

  1. Условия не являются взаимоисключающими, поэтому один и тот же экран отображается несколько раз.

  2. Один и тот же экран отображается в ветви «else» нескольких троичных операторов.

Решение состоит в том, чтобы удалить это дублирование.

Самый простой подход заключается в том, чтобы убедиться, что все условия являются взаимоисключающими и что каждая ветвь «else» отображает уникальный экран. Прямо сейчас вашими условиями являются hasSelectedLanguage и !hasCompletedIntro amp;amp; hasSelectedLanguage , которые оба могут быть истинными одновременно. Insead, вы могли бы изменить их на hasCompletedIntro amp;amp; hasSelectedLanguage и !hasCompletedIntro amp;amp; hasSelectedLanguage , которые не могут быть одновременно истинными (и в любом случае соответствуют вашему словесному описанию).

Одним из решений является вложение троичных операторов так, чтобы выполнялась только одна ветвь:

 { <condition1> ? <screens> : (<condition2> ? <screens> : <screens>)}
  

Но когда вы заполните это фактическим JSX, вложенность и отступы будут ужасающими. Вместо этого я предлагаю использовать код JavaScript перед return :

 render() {
    let screens = <default screens>;
    if (<condition1>) {
        screens = <screens>;
    } else if (<condition2>) {
        screens = <screens>;
    }

    return (
        <RootStack.Navigator>
            {screens}
        </RootStack.Navigator>
    ;
}
  

if Логика может быть любой, какой вы хотите, чтобы выполнить работу. Это полностью отделяет эту логику от фактического рендеринга.

Комментарии:

1. Привет, спасибо, что попробовали! К сожалению, это не работает. Добавление правки прямо сейчас