【问题标题】:How can I render a Tab Item for React Navigation Material Bottom Tab based on store value?如何根据商店价值为 React Navigation Material 底部选项卡呈现选项卡项?
【发布时间】:2019-07-23 20:40:05
【问题描述】:

我正在使用 React Navigation Material 底部选项卡,我需要添加一个基于商店值的选项。 我有一个经过身份验证的用户的材料底部选项卡,然后我想从商店获取用户类型值并根据我的减速器的值呈现一个选项卡项。

我尝试了以下解决方案,但我总是得到存储初始状态。

createMaterialBottomTabNavigator(
  {
    Events: {
      screen: EventsStack,
      navigationOptions: {
        tabBarLabel: 'Agenda',
        tabBarIcon: ({ tintColor }) => (
          <MaterialCommunityIcons name="calendar" size={ICON_SIZE} color={tintColor} />
        ),
      },
    },
    ...((() => {
      const userKind = store.getState() && store.getState().auth.user.kind;

      return userKind === 'p';
    })() && {
      Consultations: {
        screen: PatientsStack,
        navigationOptions: {
          tabBarLabel: 'Atendimentos',
          tabBarIcon: ({ tintColor }) => (
            <MaterialCommunityIcons name="doctor" size={ICON_SIZE} color={tintColor} />
          ),
        },
      },
    }),
    Patients: {
      screen: PatientsStack,
      navigationOptions: {
        tabBarLabel: 'Pacientes',
        tabBarIcon: ({ tintColor }) => (
          <MaterialCommunityIcons name="account-multiple" size={ICON_SIZE} color={tintColor} />
        ),
      },
    },
    Settings: {
      screen: SettingsStack,
      navigationOptions: {
        tabBarLabel: 'Ajustes',
        tabBarIcon: ({ tintColor }) => (
          <MaterialCommunityIcons name="settings" size={ICON_SIZE} color={tintColor} />
        ),
      },
    },
  },
  {
    initialRouteName: 'Events',
    labeled: false,
    shifting: false,
    activeTintColor: Colors.dsBlue,
    barStyle: {
      borderTopWidth: 1,
      borderTopColor: Colors.dsSky,
      backgroundColor: Colors.colorWhite,
    },
    tabBarOptions: {
      activeTintColor: Colors.dsBlue,
      activeBackgroundColor: Colors.dsSkyLight,
      inactiveTintColor: Colors.dsInkLighter,
      inactiveBackgroundColor: Colors.dsSkyLight,
      upperCaseLabel: false,
      labelStyle: {
        fontSize: 11,
      },
      style: {
        backgroundColor: Colors.dsSkyLight,
      },
      showIcon: true,
      pressColor: Colors.dsSkyLight,
      indicatorStyle: {
        backgroundColor: Colors.dsBlue,
      },
    },
  },
)

我想根据我的商店价值有条件地呈现Consultations 标签项。

【问题讨论】:

    标签: react-native react-redux conditional-statements react-navigation


    【解决方案1】:

    在导航器中使用 store.getState() 将为您提供初始存储,但正如您所指出的,当存储更新时不会再次调用它,因此导航器永远不会改变。

    在状态更改时更新导航的解决方案是使用连接到 Redux 存储的组件。

    假设您想根据 Redux 存储中的值更改选项卡的标题。

    在这种情况下,您只需像这样定义一个Label.js 组件:

    import React from 'react';
    import { connect } from 'react-redux';
    import { Text } from 'react-native';
    
    
    const Label = ({ user }) => {
      if (!user) return 'Default label';
      return <Text>{user.kind}</Text>;
    };
    
    
    function mapStateToProps(state) {
      return { user: state.auth.user };
    }
    
    export default connect(mapStateToProps)(Label);
    

    在这里,我们假设您有一个 reducer,它会在您的商店中的 auth 键发生更改时使用用户对象进行更新。

    现在您只需在导航中导入&lt;Label /&gt;

    import Label from './Label';
    
    export default createMaterialBottomTabNavigator({
      Events: {
        screen: EventsStack,
        navigationOptions: {
          tabBarLabel: <Label />,
        },
      },
    });
    

    瞧!每当您在商店中更新 auth.user.kind 时,标签导航都会更新。


    现在我知道,在您的情况下,您想要一些比根据商店更新标签更复杂的东西,您想要动态显示或隐藏标签。

    不幸的是,react-navigation 还没有为给定的选项卡提供hideTab 选项。有一个tabBarVisible 选项,但它仅适用于整个栏,而不是单个选项卡。

    使用标签,我们设法通过将组件连接到商店来做到这一点。但是我们应该在这里定位什么组件呢?

    解决方法是使用tabBarComponent 选项。它允许我们覆盖组件以用作标签栏。所以我们只需要用一个连接到商店的组件来覆盖它,我们就有了我们的动态标签栏!

    现在我们的 createMaterialBottomTabNavigator 变为:

    import WrappingTabBar from './WrappingTabBar';
    
    export default createMaterialBottomTabNavigator({
      Events: {
        screen: EventsStack,
        navigationOptions: {
          tabBarLabel: 'Agenda',
        },
      },
      Consultations: {
        screen: PatientsStack,
        navigationOptions: {
          tabBarLabel: 'Atendimentos',
        },
      },
    }, {
      tabBarComponent: props => <WrappingTabBar {...props} />, // Here we override the tab bar component
    });
    

    我们在WrappingTabBar.js 中定义&lt;WrappingTabBar&gt;,方法是渲染连接到商店的基本BottomTabBar,过滤掉导航状态下我们不想要的路线。

    import React from 'react';
    import { connect } from 'react-redux';
    import { BottomTabBar } from 'react-navigation';
    
    const TabBarComponent = props => <BottomTabBar {...props} />; // Default bottom tab bar
    
    const WrappingTabBar = ({ navigation, user, ...otherProps }) => (
      <TabBarComponent
        {...otherProps}
        navigation={{
          ...navigation,
          state: {
            ...navigation.state,
            routes: navigation.state.routes.filter(r => r.routeName !== 'Consultations' || (user && user.kind === 'p')), // We remove unwanted routes
          },
        }}
      />
    );
    
    
    function mapStateToProps(state) {
      return { user: state.auth.user };
    }
    
    export default connect(mapStateToProps)(WrappingTabBar);
    

    这一次,每当您的 auth reducer 收到 auth.user 的新值时,它都会更新存储。由于WrappingTabBar 已连接到存储,它再次呈现新值auth.user.kind。如果值为“p”,则对应于第二个屏幕的路由从导航状态中移除,并且选项卡被隐藏。

    就是这样!我们最终得到了一个选项卡导航,它可以根据 Redux 存储中的值动态显示选项卡。

    【讨论】:

    • 它适用于 createBottomTabNavigator 但不幸的是,createMaterialBottomTabNavigator 没有属性 tabBarComponent :(
    • 这种方法还有一个错误,当我触摸一个选项卡时,它会将另一个选项卡依次标记为焦点。这就像我有一个标签计数。如果我触摸第二个位置的患者选项卡,它将标记为聚焦第三个位置的设置选项卡。当条件过滤“咨询”选项卡时会出现此错误。
    • 你能帮我解决类似的问题吗?stackoverflow.com/questions/61940177/…
    猜你喜欢
    • 1970-01-01
    • 2023-02-04
    • 1970-01-01
    • 2020-06-01
    • 1970-01-01
    • 1970-01-01
    • 2018-12-04
    • 2022-01-11
    • 1970-01-01
    相关资源
    最近更新 更多