Навигационный эксперимент - размонтирование вкладок

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

Проблемы

Позволяет сказать, что я прокрутил несколько сообщений, и когда я меняю вкладку, она начнется сверху. (Обходной путь может заключаться в сохранении положения прокрутки в состоянии редукции).

Вот пример кода, который я использую для навигации Tabbed Experimental Navigation

Ответ 1

Вы должны изменить подход к TabBar.

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

Важно понимать разницу между методами Navigator.

  • Когда вы pop маршрут, он размонтируется, и активный индекс перемещается в последний. Поскольку последний сохраняется в состоянии, он будет восстановлен, поскольку он был ранее оказанных (скорее всего, может произойти изменение реквизита). Повторное использование маршрута popped полностью повторит сцену (это произойдет с вами).

  • Когда вы push маршрут, ничего не размонтируется, новый маршрут монтируется.

  • Когда вы jumpToIndex трассируете, снова ничего не монтируется, таким образом прыгая
    между маршрутами восстанавливает сцены так, как они были (опять же, если реквизит изменился сцена будет перезаписана).

Итак, я не думаю, что это правильно:

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

... вы отключите маршруты с неправильными действиями навигации.

Также, что сейчас отличается, NavigationCardStack не создает собственное состояние, оно передается извне, что дает вам большую гибкость. И также хорошо, что вы можете использовать редукторы, предоставляемые Facebook для общих действий (например, push, pop, jumpToIndex, они являются частью Navigation Utils).

У вас есть полный пример о том, как создать navigationState и его редукторы здесь, поэтому я не собираюсь это объяснять, просто иду дать представление о том, как решить вашу проблему.

[UPDATE] Пример теперь работает!

import React from 'react';
import { NavigationExperimental, View, Text, StyleSheet } from 'react-native';

const {
  CardStack: NavigationCardStack,
  StateUtils: NavigationStateUtils,
} = NavigationExperimental;

const style = StyleSheet.create({
  screen: {
    flex: 1,
  },
  screenTitle: {
    marginTop: 50,
    fontSize: 18,
  },
  pushNewScreenLabel: {
    marginVertical: 10,
    fontSize: 15,
    fontWeight: "bold",
  },
  goBackLabel: {
    fontSize: 15,
  },
  tabBarWrapper: {
    position: 'absolute',
    height: 50,
    bottom: 0,
    left: 0,
    right: 0,
    top: null,
    backgroundColor: 'grey',
    flexDirection: 'row',
    flex: 0,
    alignItems: 'stretch',
  },
  tabBarItem: {
    flex: 1,
    justifyContent: 'center',
    backgroundColor: 'red',
  },
});

export class TabBar extends React.Component {
  constructor(props, context) {
    super(props, context);

    this.jumpToTab = this.jumpToTab.bind(this);

    // Create state
    this.state = {
      navigationState: {
        // Active route, will  be rendered as default
        index: 0,
        // "tab-s" represents route objects
        routes: [
          { name: 'Tab1', key: '1' },
          { name: 'Tab2', key: '2' },
          { name: 'Tab3', key: '3' },
          { name: 'Tab4', key: '4' }],
      },
    };
  }

  jumpToTab(tabIndex) {
    const navigationState = NavigationStateUtils.jumpToIndex(this.state.navigationState, tabIndex);
    this.setState({ navigationState });
  }

  renderScene({ scene }) {
    return <Tab tab={scene.route} />;
  }

  render() {
    const { navigationState } = this.state;
    return (
      <View style={style.screen}>
        <NavigationCardStack
          onNavigate={() => {}}
          navigationState={navigationState}
          renderScene={this.renderScene}
        />
        <View style={style.tabBarWrapper}>
          {navigationState.routes.map((route, index) => (
            <TabBarItem
              key={index}
              onPress={this.jumpToTab}
              title={route.name}
              index={index}
            />
            ))}
        </View>
      </View>
    );
  }
}

class TabBarItem extends React.Component {
  static propTypes = {
    title: React.PropTypes.string,
    onPress: React.PropTypes.func,
    index: React.PropTypes.number,
  }

  constructor(props, context) {
    super(props, context);
    this.onPress = this.onPress.bind(this);
  }
  onPress() {
    this.props.onPress(this.props.index);
  }
  render() {
    return (
      <Text style={style.tabBarItem} onPress={this.onPress}>
        {this.props.title}
      </Text>);
  }
}

class Tab extends React.Component {
  static propTypes = {
    tab: React.PropTypes.object,
  }

  constructor(props, context) {
    super(props, context);
    this.goBack = this.goBack.bind(this);
    this.pushRoute = this.pushRoute.bind(this);
    this.renderScene = this.renderScene.bind(this);
    this.state = {
      navigationState: {
        index: 0,
        routes: [{ key: '0' }],
      },
    };
  }

  // As in TabBar use NavigationUtils for this 2 methods
  goBack() {
    const navigationState = NavigationStateUtils.pop(this.state.navigationState);
    this.setState({ navigationState });
  }

  pushRoute(route) {
    const navigationState = NavigationStateUtils.push(this.state.navigationState, route);
    this.setState({ navigationState });
  }

  renderScene({ scene }) {
    return (
      <Screen
        goBack={this.goBack}
        goTo={this.pushRoute}
        tab={this.props.tab}
        screenKey={scene.route.key}
      />
    );
  }

  render() {
    return (
      <NavigationCardStack
        onNavigate={() => {}}
        navigationState={this.state.navigationState}
        renderScene={this.renderScene}
      />
    );
  }
}

class Screen extends React.Component {
  static propTypes = {
    goTo: React.PropTypes.func,
    goBack: React.PropTypes.func,
    screenKey: React.PropTypes.string,
    tab: React.PropTypes.object,
  }

  constructor(props, context) {
    super(props, context);
    this.nextScreen = this.nextScreen.bind(this);
  }

  nextScreen() {
    const { goTo, screenKey } = this.props;
    goTo({ key: `${parseInt(screenKey) + 1}` });
  }

  render() {
    const { tab, goBack, screenKey } = this.props;
    return (
      <View style={style.screen}>
        <Text style={style.screenTitle}>
          {`Tab ${tab.key} - Screen ${screenKey}`}
        </Text>
        <Text style={style.pushNewScreenLabel} onPress={this.nextScreen}>
          Push Screen into this Tab
        </Text>
        <Text style={style.goBackLabel} onPress={goBack}>
          Go back
        </Text>
      </View>
    );
  }
}
## TBD немного больше очистить..