Как исправить «navigation.state не определено» в пользовательском компоненте реагировать на навигацию? - PullRequest
0 голосов
/ 01 ноября 2019

Я пытаюсь использовать пользовательский компонент (свойство tabBarComponent) для своего приложения React Native, используя createMaterialTopTabNavigator из "react-native-tabs", компонентом является BottomNavigation из "react-native-paper".

IЯ скопировал почти весь код из https://github.com/react-navigation/material-bottom-tabs, так как это единственный источник, который я нашел для использования BottomNavigation в качестве пользовательского компонента

У меня есть 3 основных кода: TabNavigator (component)

class CustomTabNavigator extends React.Component {
_getColor = ({ route }) => {
  const { descriptors } = this.props;
  const descriptor = descriptors[route.key];
  const options = descriptor.options;

  if (this.context === 'dark' && options.tabBarColorDark) {
    return options.tabBarColorDark;
  } else if (options.tabBarColorLight) {
    return options.tabBarColorLight;
  } else {
    return options.tabBarColor;
  }
};

_getactiveColor = () => {
  let { activeColor, activeColorLight, activeColorDark } = this.props;

  if (this.context === 'dark' && activeColorDark) {
    return activeColorDark;
  } else if (activeColorLight) {
    return activeColorLight;
  } else {
    return activeColor;
  }
};

_getInactiveColor = () => {
  let { inactiveColor, inactiveColorLight, inactiveColorDark } = this.props;

  if (this.context === 'dark' && inactiveColorDark) {
    return inactiveColorDark;
  } else if (inactiveColorLight) {
    return inactiveColorLight;
  } else {
    return inactiveColor;
  }
};

_getBarStyle = () => {
  let { barStyle, barStyleLight, barStyleDark } = this.props;

  return [barStyle, this.context === 'dark' ? barStyleDark : barStyleLight];
};

_isVisible() {
  const { navigation, descriptors } = this.props;
  const { state } = navigation;
  const route = state.routes[state.index];
  const options = descriptors[route.key].options;
  return options.tabBarVisible;
}

_renderIcon = ({
  route,
  focused,
  color,
}) => {
  return this.props.renderIcon({ route, focused, tintColor: color });
};

render() {
  const {
    navigation,
    descriptors,
    ...rest
  } = this.props;

  const activeColor = this._getactiveColor();
  const inactiveColor = this._getInactiveColor();
  const barStyle = this._getBarStyle();

  const isVisible = this._isVisible();
  const extraStyle =
    isVisible === false
      ? {
          display: 'none',
          position: undefined,
        }
      : null;

  return (
    <BottomNavigation
      {...rest}
      activeColor={activeColor}
      inactiveColor={inactiveColor}
      renderIcon={this._renderIcon}
      barStyle={[barStyle, extraStyle]}
      navigationState={navigation.state}
      getColor={this._getColor}
    />
  )
}
}

TabNavigation (navigator)

class CustomTabNavigation extends React.Component {
_renderScene = ({ route }) => {
  const { screenProps, descriptors } = this.props;
  const descriptor = descriptors[route.key];
  const TabComponent = descriptor.getComponent();
  return (
    <SceneView
      screenProps={screenProps}
      navigation={descriptor.navigation}
      component={TabComponent}
    />
  );
};

_renderIcon = ({
  route,
  focused,
  tintColor,
  horizontal = false,
}) => {
  const { descriptors } = this.props;
  const descriptor = descriptors[route.key];
  const options = descriptor.options;

  if (options.tabBarIcon) {
    return typeof options.tabBarIcon === 'function'
      ? options.tabBarIcon({ focused, tintColor, horizontal })
      : options.tabBarIcon;
  }

  return null;
};

_getLabelText = ({ route }) => {
  const { descriptors } = this.props;
  const descriptor = descriptors[route.key];
  const options = descriptor.options;

  if (options.tabBarLabel) {
    return options.tabBarLabel;
  }

  if (typeof options.title === 'string') {
    return options.title;
  }

  return route.routeName;
};

_getAccessibilityLabel = ({ route }) => {
  const { descriptors } = this.props;
  const descriptor = descriptors[route.key];
  const options = descriptor.options;

  if (typeof options.tabBarAccessibilityLabel !== 'undefined') {
    return options.tabBarAccessibilityLabel;
  }

  const label = this._getLabelText({ route });

  if (typeof label === 'string') {
    const { routes } = this.props.navigation.state;
    return `${label}, tab, ${routes.indexOf(route) + 1} of ${
      routes.length
    }`;
  }

  return undefined;
};

_getTestID = ({ route }) => {
  const { descriptors } = this.props;
  const descriptor = descriptors[route.key];
  const options = descriptor.options;

  return options.tabBarTestID;
};

_getBadge = ({ route }) => {
  const { descriptors } = this.props;
  const descriptor = descriptors[route.key];
  const options = descriptor.options;

  return options.tabBarBadge;
};

_makeDefaultHandler = ({
  route,
  navigation,
}) => () => {
  if (navigation.isFocused()) {
    if (route.hasOwnProperty('index') && route.index > 0) {
      navigation.dispatch(StackActions.popToTop({ key: route.key }));
    } else {
      navigation.emit('refocus');
    }
  } else {
    this._jumpTo(route.routeName);
  }
};

_handleTabPress = ({ route }) => {
  this._isTabPress = true;
  Promise.resolve().then(() => (this._isTabPress = false));

  const { descriptors } = this.props;
  const descriptor = descriptors[route.key];
  const { navigation, options } = descriptor;

  const defaultHandler = this._makeDefaultHandler({ route, navigation });

  if (options.tabBarOnPress) {
    options.tabBarOnPress({ navigation, defaultHandler });
  } else {
    defaultHandler();
  }
};

_handleIndexChange = index => {
  if (this._isTabPress) {
    this._isTabPress = false;
    return;
  }

  this._jumpTo(this.props.navigation.state.routes[index].routeName);
};

_jumpTo = routeName => {
  const { navigation } = this.props;

  navigation.dispatch(
    SwitchActions.jumpTo({
      routeName,
      key: navigation.state.key,
    })
  );
};

_isTabPress = false;

render() {
  const {
    descriptors,
    navigation,
    screenProps,
    navigationConfig,
  } = this.props;
  const { state } = navigation;
  const route = state.routes[state.index];
  const descriptor = descriptors[route.key];
  const options = {
    ...navigationConfig,
    ...descriptor.options,
  };

  return (
    <CustomTabNavigator
      {...options}
      getLabelText={this._getLabelText}
      getAccessibilityLabel={this._getAccessibilityLabel}
      getTestID={this._getTestID}
      getBadge={this._getBadge}
      renderIcon={this._renderIcon}
      renderScene={this._renderScene}
      onIndexChange={this._handleIndexChange}
      onTabPress={this._handleTabPress}
      navigation={navigation}
      descriptors={descriptors}
      screenProps={screenProps}
    />
  );
}
}

Main navigation

const TabNavigator = createStackNavigator(
{
  TabsStack: {
    ...,
    {
      ...,
      tabBarComponent: ({ props }) => <CustomTabNavigation {...props} />
    })
  },
}
);

Я ожидал, что смогу использовать swipeEnabled функция (анимированный переход к каждому экрану и обратно) из createMaterialTopTabNavigator из режима реагирования, а также более привлекательная панель вкладок, но она говорит, что 'navigation.state is undefined' в функции рендеринга CustomTabNavigation (строкаconst { state } = navigation;), но я не могу понять причину.

1 Ответ

0 голосов
/ 01 ноября 2019

Я думаю, что здесь есть ошибка: tabBarComponent: ({ props }) => <CustomTabNavigation {...props} /> должно быть tabBarComponent : props => <CustomTabNavigation {...props} /> или просто tabBarComponent: CustomTabNavigation

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

Но учтите, что ни в Android, ни в iOS рекомендации по дизайну не добавляют жесты смахивания к нижним вкладкам, поэтому UX будет несовместимым. Обычно верхняя панель вкладок имеет жест смахивания, потому что сложнее добраться до верхней панели пальцем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...