将道具传递到动态的TabNavigator

时间:2019-01-10 16:39:58

标签: javascript react-native react-navigation

(也在https://github.com/react-navigation/react-navigation/issues/4059#issuecomment-453100740中询问)

我已经用动态的TabNavigator替换了静态的TabNavigator,并且一切似乎正常。
但是,已按预期方式通过的道具不再以相同的方式通过。
任何想法如何解决这个问题?通过在静态解决方案中传递道具,或通过传递所需的道具(this.props.navigation)。

这是我的顶级导航器:

export default createDrawerNavigator({
    Drawer: MainDrawerNavigator,
    Main: MainTabNavigator
}, {
  contentComponent: props => <Drawer {...props} />,
});

这是静态Tab导航器和堆栈之一:

const ProfileStack = createStackNavigator({
  Profile: {
    screen: Profile,
    navigationOptions: () => ({
        title: 'Profile'
    })
  }
}, {
  initialRouteName: 'Profile'
});

ProfileStack.navigationOptions = {
  tabBarLabel: 'Profile',
  tabBarIcon: ({ focused }) => (
    <TabBarIcon
      focused={focused}
      name= 'md-person' />
  )};

const MainTabNavigator = createBottomTabNavigator({
  RequestStack,
  ProfileStack
}, {
    headerMode: 'none',
    initialRouteName: ProfileStack
});

Profile屏幕:

import React from 'react';
import { View, TouchableOpacity } from 'react-native';
import { Container, Header, Content, Text
} from 'native-base';

export default class Profile extends React.Component {
  static navigationOptions = {
    header: null
  };

  constructor(props) {
    super(props);
  }

  render() {
    console.log('in Profile. this.props:');
    console.log(this.props);
    return (
        <Container style={styles.container}>
          <Header>
              <TouchableOpacity
                onPress={() => this.props.navigation.openDrawer()}>
                 <Icon name="md-more" />
              </TouchableOpacity>
          </Header>
          <Content>

           <Text>aaa</Text>
          </Content>
        </Container>
    );
  }
}

单击“ md-more”图标将打开抽屉(this.props.navigation.openDrawer)。

使用动态标签导航器-openDrawer不再传递给“配置文件”。

当我用下面的Dynamic替换上面的静态Tab Navigator时,this.props.navigation.openDrawer没有通过,因此未在“配置文件”中定义(配置文件不变,更改仅在底部选项卡中航海家)。

这是动态的标签浏览器:

export default class DynamicTabNavigator extends React.Component {

  constructor(props) {
    super(props);
  }

  _tabNavigator() {
    let tabs = {};
    const a = 2; 
    if (a > 1) {   // the actual line is obviously different, I am trying to simplify the example
      tabs = { RequestStack, ManageStack, MessagesStack, ProfileStack };
    } else {
      tabs = { WorkStack, ManageStack, MessagesStack, ProfileStack };
    }

    console.log('in _tabNavigator. this.props.navigation:');
    console.log(this.props.navigation);
    return createBottomTabNavigator(tabs, {
        headerMode: 'none',
    });
  }

  render() {
    const Tabs = this._tabNavigator.bind(this)();
    return (
      <Tabs/>
    );
  }
}

这是DynamicTabNavigator的console.log()的输出:

in _tabNavigator. this.props.navigation:
 Object {
   "actions": Object {
     "closeDrawer": [Function closeDrawer],
     "goBack": [Function goBack],
     "navigate": [Function navigate],
     "openDrawer": [Function openDrawer],
     "setParams": [Function setParams],
     "toggleDrawer": [Function toggleDrawer],
   },
   "addListener": [Function addListener],
   "closeDrawer": [Function anonymous],
   "dangerouslyGetParent": [Function anonymous],
   "dispatch": [Function anonymous],
   "getChildNavigation": [Function getChildNavigation],
   "getParam": [Function anonymous],
   "getScreenProps": [Function anonymous],
   "goBack": [Function anonymous],
   "isFocused": [Function isFocused],
   "navigate": [Function anonymous],
   "openDrawer": [Function anonymous],
   "router": undefined,
   "setParams": [Function anonymous],
   "state": Object {
     "key": "Main",
     "params": undefined,
     "routeName": "Main",
   },
   "toggleDrawer": [Function anonymous],
 }

这是DynamicTabNavigator到位时Profile的console.log()的输出:

(我希望所有道具(例如openDrawer)都与DynamicTabNavigator相同,而且我不明白为什么它们不是这样)

 in Profile. this.props:
 Object {
   "appMode": "WORK_MODE",
   "dispatch": [Function anonymous],
   "navigation": Object {
     "actions": Object {
       "dismiss": [Function dismiss],
       "goBack": [Function goBack],
       "navigate": [Function navigate],
       "pop": [Function pop],
       "popToTop": [Function popToTop],
       "push": [Function push],
       "replace": [Function replace],
       "reset": [Function reset],
       "setParams": [Function setParams],
     },
     "addListener": [Function addListener],
     "dangerouslyGetParent": [Function anonymous],
     "dismiss": [Function anonymous],
     "dispatch": [Function anonymous],
     "getChildNavigation": [Function getChildNavigation],
     "getParam": [Function anonymous],
     "getScreenProps": [Function anonymous],
     "goBack": [Function anonymous],
     "isFocused": [Function isFocused],
     "navigate": [Function anonymous],
     "pop": [Function anonymous],
     "popToTop": [Function anonymous],
     "push": [Function anonymous],
     "replace": [Function anonymous],
     "reset": [Function anonymous],
     "router": undefined,
     "setParams": [Function anonymous],
     "state": Object {
       "key": "id-1547113035295-8",
       "routeName": "Profile",
     },
   },
   "screenProps": undefined,
 }

有关@dentemm解决方案的问题:

我不确定如何实施您的解决方案...

  • 让我们说,我在TabRoutes中有您在示例中指定的三个屏幕
  • 在我的redux状态下,我有一个名为“ appState”的变量。如果为true,则要显示第一和第二,如果为false,则要显示第三和第三。
  • 这是我根据您的示例编写的代码。但是,我不确定CustomTabBar中包含哪个组件。你能详细说明吗?

    import React from 'react';
    class CustomTabBar extends React.Component {
    
    render() {
    // a tab bar component has a routes object in the navigation state
    const { navigation } = this.props;
    
      // appState is extracted from redux state, see below
      if (this.props.appState) {
        return (
          <View>
            <???
              name='First'
              onPress={this.navigationHandler}
              focused={navigation.state.index === index}
            />
            <???
              name='Second'
              onPress={this.navigationHandler}
              focused={navigation.state.index === index}
            />
          </View>
        );
      } else {
        return (
          <View>
            <???
              name='First'
              onPress={this.navigationHandler}
              focused={navigation.state.index === index}
            />
            <???
              name='Third'
              onPress={this.navigationHandler}
              focused={navigation.state.index === index}
            />
          </View>
          );
        }
      }
    
      navigationHandler = (name) => {
        const {navigation} = this.props;
        navigation.navigate(name);
      }
    }
    
    const mapStateToProps = state => {
     const { appState } = state.app;
     return { appState };
    };
    
    export default connect(mapStateToProps)(CustomTabBar);
    

2 个答案:

答案 0 :(得分:3)

您还可以保持TabNavigator不变,并使用自定义TabBarItem组件创建一个自定义TabBar组件。您可以将该自定义TabBar连接到您的redux状态,并根据需要隐藏/显示自定义TabBarItems。

然后像往常一样简单地将所有可能的路由添加到TabNavigator。

路线

const TabRoutes = createBottomTabNavigator({
  First: {screen: SomeScreen},
  Second: {screen: SomeStack},
  Third: {screen: AnotherStack}
},{
  initialRouteName: 'First',
  tabBarComponent: CustomTabBar
});

CustomTabBar

关于如何隐藏选项卡栏项目的一些基本示例,因此显然需要根据自己的要求进行调整

import CustomTabBarItem from '...'  ; 

class CustomTabBar extends React.Component {

  render() {

    // a tab bar component has a routes object in the navigation state
    const {navigation, appState} = this.props;
    const routes = navigation.state.routes;

    return (
      <View style={styles.container}>
        // You map over all existing routes defined in TabNavigator
        {routes.map((route, index) => {

              // This could be improved, but it's just to show a possible solution
              if (appState && route.routeName === 'x') {
                return <View/>;
              } else if (!appState && route.routeName === 'y') {
                return <View/>;
              }

              return (<CustomTabBarIcon
                key={route.key}
                name={route.routeName}
                onPress={this.navigationHandler}
                focused={navigation.state.index === index}
                appState={appState}
              />);
        })}
      </View>
    );
  }

  navigationHandler = (name) => {

    const {navigation} = this.props;
    navigation.navigate(name);
  }
}

const styles = StyleSheet.create({
  container: {
    width: '100%',
    flexDirection: 'row'
  }
})

const mapStateToProps = (state) => {
  return {
    appState: state.app.appState // boolean
  };
};

export default connect(mapStateToProps)(CustomTabBar);

CustomTabBarItem

class CustomTabBarItem extends React.PureComponent {
  render() {

    const {name, focused} = this.props;

    return (
      <View style={styles.tabItem}>
        // Some icon maybe
        <Text style={/*different style for focused / unfocused tab*/}>{name}</Text>
      </View>
    );
  }
}

const styles = StyleSheet.create({
  tabItem: {
    flex: 1
  }
})

答案 1 :(得分:1)

好吧,看完代码后,我看到了问题所在……问题是..您没有以正确的方式嵌套导航道具。当您在抽屉式导航器中嵌套一个普通的选项卡导航器时,它可以很好地工作,因为您没有渲染任何东西,所以您正在做它的反应导航方式。 但是..当您尝试使用动态选项卡导航器时,没有将选项卡导航器返回到抽屉式导航器,而是返回了组件 export function tabNavigator(){ let tabs = {}; const a = 2; if (a > 1) { // the actual line is obviously different, I am trying to simplify the example tabs = { RequestStack, ManageStack, MessagesStack, ProfileStack }; } else { tabs = { WorkStack, ManageStack, MessagesStack, ProfileStack }; } // console.log('in _tabNavigator. this.props.navigation:'); //console.log(navigation); return createBottomTabNavigator(tabs, { headerMode: 'none', }); } ,在他的渲染功能中,您有一个导航器... 所以..您有2种可能的解决方案...  第一个只是使用一个函数并在没有自定义组件的情况下调用它

import {tabNavigator} from './TabNavigator'
    const Tabs = tabNavigator()
    export default createDrawerNavigator({
        Drawer: MainDrawerNavigator,
        Main: Tabs
    }, {
      contentComponent: props => <Drawer {...props} />,
    });

并在您的根导航器中

_tabNavigator() {
    let tabs = {};
    const a = 2; 
    if (a > 1) {   // the actual line is obviously different, I am trying to simplify the example
      tabs = { RequestStack: {screen:<RequestStack navigation={this.props.navigation}/>, navigationOptions: () => ({
    tabBarLabel:'Request',
    tabBarIcon:<YourComponent/>})}, 
               ManageStack:{screen:<ManageStack navigation={this.props.navigation}/>}, MessagesStack:{screen:<MessagesStack navigation={this.props.navigation}/>},
               ProfileStack:{screen:<ProfileStack navigation={this.props.navigation}/>}};
    } else {
      tabs = { WorkStack, ManageStack, MessagesStack, ProfileStack }; //repeat
    }

    console.log('in _tabNavigator. this.props.navigation:');
    console.log(this.props.navigation);
    return createBottomTabNavigator(tabs, {
        headerMode: 'none',
    });

不知道这是否行得通

第二个解决方案

手动将导航道具传递给dynamyc Tabnavigator的所有屏幕,这确实很丑陋,但是当您将导航器放入组件内部时,这是一种解决方法

const ProfileStack = ({props}) => createStackNavigator({
  Profile: {
    screen: <Profile navigation={props.navigation}/>,
    navigationOptions: () => ({
        title: 'Profile'
    })
  }
}, {
  initialRouteName: 'Profile'
});

提示:请勿在组件内部进行动态导航,如果不手动传递导航道具,则会丢失

编辑N2:

{amount: "x", xParty: "x", yAction: "x", zParty: "x", objectKey: "-ggj34h3j4h3hj4hj3")