Передача реквизита в динамический TabNavigator - PullRequest
0 голосов
/ 10 января 2019

(также спрашивается в https://github.com/react-navigation/react-navigation/issues/4059#issuecomment-453100740)

Я заменил статический TabNavigator на динамический, и кажется, что все работает.
Однако реквизиты, которые были переданы как ожидалось, больше не передаются таким же образом.
Есть идеи как это исправить? Либо передавая реквизиты, как в статическом решении, либо передавая необходимые реквизиты (this.props.navigation).

Это мой лучший навигатор:

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

Это статический Tab Navigator и один из стеков:

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 больше не передается в «Профиль».

когда я заменяю вышеуказанный статический навигатор вкладок на следующий динамический, this.props.navigation.openDrawer не передается и поэтому не определяется в «Профиле» (профиль не изменяется, изменение только на нижней вкладке навигатор).

Вот динамический Tab Navigator:

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/>
    );
  }
}

Это вывод console.log () из DynamicTabNavigator:

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],
 }

Это вывод console.log () из профиля, когда DynamicTabNavigator находится на месте:

(я ожидал, что все реквизиты, как, например, 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 есть три экрана, которые вы указали в своем примере
  • В моем состоянии избыточности у меня есть переменная appState. Если это правда, я хочу отобразить первый и второй, если ложь первый и третий.
  • Вот код, который я написал на основе вашего примера. Однако я не уверен, какой компонент включен в 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 голосов
/ 11 января 2019

Вы также можете оставить TabNavigator как есть и создать собственный компонент TabBar с пользовательскими компонентами TabBarItem. Вы можете подключить этот пользовательский TabBar к вашему состоянию приставки и скрыть / отобразить пользовательские 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
  }
})
0 голосов
/ 11 января 2019

Хорошо, посмотрев на ваш код, я вижу, в чем проблема ... проблема в том ... что вы не правильно вкладываете навигацию. Когда вы вкладываете обычный tabnavigator в боксерский движок, он работает нормально, потому что вы ничего не рендерите, вы делаете это способом реакции навигации. Но ... когда вы пытаетесь использовать динамический tabnavigator, вы не возвращаете tabnavigator вCLN, вы возвращаете КОМПОНЕНТ export default class DynamicTabNavigator extends React.Component {}, а внутри его функции рендеринга у вас есть табнавигатор ... Итак ... у вас есть 2 возможных решения ... первая использует только функцию и вызывает ее без специального компонента

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',
    });
}

и в вашем корневом навигаторе

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

Не знаю, сработает ли это

Второй раствор

вручную передавать реквизиты навигации на все экраны tabnavigator Dynamyc, это действительно уродливо, но это обходной путь, когда вы помещаете навигатор внутри компонента

_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',
    });

protip: не выполнять динамическую навигацию внутри компонента, навигационная опора будет потеряна, если вы не передадите ее вручную

РЕДАКТИРОВАТЬ N2:

const ProfileStack = ({props}) => createStackNavigator({
  Profile: {
    screen: <Profile navigation={props.navigation}/>,
    navigationOptions: () => ({
        title: 'Profile'
    })
  }
}, {
  initialRouteName: 'Profile'
});
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...