Как перемещаться между различными вложенными стеками в режиме реагирования

Цель

Используя интерактивную навигацию, перейдите с экрана в навигаторе к экрану в другом навигаторе.

Более детально

Если у меня есть следующая структура Navigator:

  • Родительский навигатор
    • Вложенный навигатор 1
      • экран A
      • экран В
    • Вложенный навигатор 2
      • экран C
      • экран D

как мне перейти с экрана D под вложенным навигатором 2, на экран A под вложенным навигатором 1? Прямо сейчас, если я попытаюсь перейти на navigation.navigate на экран A с экрана D, появится сообщение о том, что он не знает о экране A, только экран C и D.

Я знаю, что это было задано в различных формах в разных местах на этом сайте, а также в GitHub (https://github.com/react-navigation/react-navigation/issues/983, https://github.com/react- навигация/реакция-навигация/проблемы/335 # issuecomment-280686611), но для чего-то такого базового, есть отсутствие четких ответов и прокрутка сотен комментариев GitHub, ищущих решение, невелика.

Возможно, этот вопрос может кодифицировать, как это сделать для всех, кто сталкивается с этой очень распространенной проблемой.

Ответ 1

Вы можете использовать третий параметр navigate для определения подэтапов.

Например, если вы хотите перейти от экрана D во вложенном навигаторе 2 к экрану A во вложенном навигаторе 1:

this.props.navigation.navigate('NestedNavigator1', {}, NavigationActions.navigate({ routeName: 'screenB' }))

Также не забудьте проверить Распространенные ошибки, если вы используете вложенные навигаторы.

Ответ 2

Реагируйте Навигация v3:

Navigation.navigate теперь принимает один объект в качестве параметра. Вы устанавливаете имя стека, затем переходите к маршруту внутри этого стека следующим образом...

navigation.navigate(NavigationActions.navigate({
    routeName: 'YOUR_STACK',
    action: NavigationActions.navigate({ routeName: 'YOUR_STACK-subRoute' })
}))

Где 'YOUR_STACK' - это то, что называется вашим стеком, когда вы его создаете...

  YOUR_STACK: createStackNavigator({ subRoute: ... })

Ответ 3

Полная свобода: синглтон с навигацией

Если у вас есть ситуация, когда у вас есть несколько стеков навигации и вспомогательных стеков, может быть сложно узнать, как получить ссылку на нужный стек, учитывая настройку React Navigation. Если бы вы могли просто ссылаться на любой конкретный стек в любой момент времени, это было бы намного проще. Вот как.

  1. Создайте синглтон, специфичный для стека, на который вы хотите сослаться где угодно.

    // drawerNavigator.js . (or stackWhatever.js)
    const nav = {}
    export default {
      setRef: ref => nav.ref = ref,
      getRef: () => nav.ref
    }
    
  2. Установите ссылку на нужный навигатор, используя navigatorOptions

    import { createBottomTabNavigator } from 'react-navigation'
    import drawerNavigation from '../drawerNavigator'
    
    const TabNavigation = createBottomTabNavigator(
      {
        // screens listed here
      },
      {
        navigationOptions: ({ navigation }) => {
          // !!! secret sauce set a reference to parent
          drawerNavigation.setRef(navigation)
          return {
            // put navigation options
          }
        }
      }
    )
    
  3. Теперь вы можете ссылаться на drawerNavigator любом месте внутри или снаружи

    // screen.js
    import drawerNavigator from '../drawerNavigator'
    
    export default class Screen extends React.Component {
      render() {
        return (
          <View>
            <TouchableHighlight onPress={() => drawerNavigator.getRef().openDrawer()}>
              <Text>Open Drawer</Text>
            </TouchableHighlight>
          </View>
        )
      }
    }
    

объяснение

На шаге 2 Tab Navigator является одним из экранов в Drawer Navigator. Навигатор по drawerNavigator.getRef().closeDrawer() должен закрывать ящик, но также и в любом месте вашего приложения, после этого шага вы можете вызывать drawerNavigator.getRef().closeDrawer(). Вы не ограничены тем, что имеете прямой доступ к props.navigation после этого шага.

Ответ 4

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

После многих испытаний я попытался передать родительский объект навигации детям и сделал вызов функции навигации, и он сработал.

Теперь приступим к вашим проблемам. Если вы хотите перейти с экрана D на экран A, выполните следующие действия.

→ Пропускать вложенные навигационные навигационные навигаторы 2 своим детям с помощью экранов.

export default class Home extends Component {
    static navigationOptions = {
        header:null
    };

    constructor(props) {
        super(props);
        this.state = {
            profileData: this.props.navigation.state.params,
            route_index: '',
        }
    }

    render() {
        return (
            <ParentNavigator screenProps={this.props.navigation} />
        );
    }
}

export const ParentNavigator = StackNavigator({
  // ScreenName : { screen : importedClassname }
  Nested1: { screen: nested1 },
  Nested2: { screen : nestes1 }
});

export const nested1 = StackNavigator({
  ScreenA: { screen: screenA },
  ScreenB: { screen : screenB }
});

export const nested2 = StackNavigator({
  ScreenC: { screen: screenC },
  ScreenD: { screen : screenD }
});

Вы можете получить навигацию у детей, используя

const {navigate} = this.props.screenProps.navigation;

Теперь этот navigate() можно использовать для перемещения между дочерними элементами.

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

Ответ 5

Я нашел также такое решение здесь:

onPress={() =>
    Promise.all([
    navigation.dispatch(
        NavigationActions.reset({
            index: 0,
            // TabNav is a TabNavigator nested in a StackNavigator
            actions: [NavigationActions.navigate({ routeName: 'TabNav' })]
        })
    )
    ]).then(() => navigation.navigate('specificScreen'))
}

Ответ 6

 const subAction = NavigationActions.navigate({ routeName: 'SignInScreen' });
      AsyncStorage.clear().then(() =>
        this.props.navigation.navigate('LoggedOut', {}, subAction));

LoggedOut - это имя стека, в котором находится экран входа.

Ответ 7

Моя цель состояла в том, чтобы все экраны аутентификации имели общий фон и все остальное приложение, используя обычный переход в стек.

По прошествии нескольких часов я обнаружил, что решение заключается в том, чтобы createStackNavigator() находился в том же файле, что и оболочка компонента. Так что вы можете успешно выставить static router как указано в документе. Это позволит избежать You should only render one navigator explicitly in your app предупреждении You should only render one navigator explicitly in your app и вы можете использовать this.props.navigation.navigate('AnyScreen') для перехода к любому вложенному экрану.

AuthRouter.js

export const AuthNavigationStack = createStackNavigator(
  {
    Login: {
      screen: Login
    },
    CreateAccount: {
      screen: CreateAccount
    }
  }
);

export default class AuthContainer extends React.Component {
  constructor( props ) {
    super( props );
  }

  static router = AuthNavigationStack.router;

  render() {
    return (
      <ImageBackground
        style={ {
          width: '100%',
          height: '100%'
        } }
        source={ require( '../Images/johannes-andersson-yosimite.jpg' ) }
        blurRadius={ 10 }
      >
        <StatusBar
          barStyle="dark-content"
          backgroundColor="transparent"
          translucent={ true }
        />
        <AuthNavigationStack navigation={ this.props.navigation } />
      </ImageBackground>
    );
  }
}

MessengerRouter.js

export const MessengerStackNavigator = createStackNavigator(
  {
    Chat: {
      screen: Chat,
    },
    User: {
      screen: User,
    },
  }
);

export default class MainContainer extends React.Component {
  constructor( props ) {
    super( props );
  }

  static router = MessengerStackNavigator.router;

  render() {
    return <MessengerStackNavigator navigation={ this.props.navigation } />;
  }
}

Router.js

import { createStackNavigator } from 'react-navigation';

import AuthRouter from './AuthRouter';
import MessengerRouter from './MessengerRouter';

export const RootNavigationStack = createStackNavigator( {
  AuthContainer: {
    screen: AuthRouter,
    navigationOptions: () => ( {
      header: null
    } )
  },
  MessengerRouter: {
    screen: MessengerRouter,
    navigationOptions: () => ( {
      header: null
    } )
  }
} );

RootContainer.js

import { RootNavigationStack } from '../Config/Router';

class RootContainer extends Component {

  render() {
    return <RootNavigationStack />;
  }
}

Заметки:

  • Передайте header: null из RootNaviagtionStack во вложенные стеки, чтобы удалить перекрывающийся заголовок

  • Если вы перейдете от Nested A к Nested B и нажмете кнопку "Назад", вы вернетесь к первому экрану в Nested B. Не большая проблема, но я не понял, как это исправить.

Ответ 8

@ZenVentzi, вот ответ для многоуровневых вложенных навигаторов, когда Nested Navigator 1 имеет Nested Navigator 1.1.

  • Родительский навигатор
    • Вложенный навигатор 1
      • Nested Navigator 1.1
        • экран A
        • экран B
    • Вложенный Навигатор 2
      • экран C
      • экран D

Мы можем просто вводить NavigationActions.navigate() несколько раз по мере необходимости.

  const subNavigateAction = NavigationActions.navigate({
    routeName: 'NestedNavigator1.1',
    action: NavigationActions.navigate({
      routeName: 'ScreenB',
      params: {},
    }),
  });
  const navigateAction = NavigationActions.navigate({
    routeName: 'NestedNavigator1',
    action: subNavigateAction,
  });
  this.props.navigation.dispatch(navigateAction);