2016-08-21 2 views
3

Панель навигации Я собираю это Ask/ответ App, и наткнулся на это препятствие:Реагировать родной: Binding сцену

Я хочу, чтобы вызвать функцию в сцене из Панель навигации. Подобно Вход приложения У меня есть кнопка в Панель навигации, чтобы представить ответ:

RightButton(route, navigator, index, navState) { 
    if (route.name=='TextInputView'){ 
    return <TouchableHighlight 
      underlayColor="transparent" 
      style={{ marginRight:13, marginTop:0}} 
      onPress={() => this.refs.TextInputView.submitSolution()}> 
     <Text style={ styles.leftNavButtonText }>Done</Text> 
     </TouchableHighlight> 
    } 

в renderscene (маршрут, навигатор) выглядит так:

if (route.name == 'TextInputView'){ 
    return <TextInputView ref="TextInputView" navigator={navigator} {...route.passProps}/> 
} 

и, конечно, в «TextInputView» у меня есть функция «submitSolution» ...

Проблема в том, что если я нахожусь на сцене и нажимаю «Готово» - я всегда получаю: «undefined не является объектом (оценка« _this2.refs.TextInputView ')

как всегда: Спасибо за помощь

ответ

9

Ну, вы можете сделать это, сохранив все, что связано с представлением в самой сцене.

Как?

Вы делаете это, вводя кнопку в навигационной панели по требованию.

Вот решение я создал для проекта, я работаю над: https://rnplay.org/apps/dS31zw

Идея заключается в том, чтобы предоставить маршрут NavBar с объектом, который имеет метку и функцию (и все, что вам нравится .. например, значки.)

В качестве бонуса вы можете ввести название тоже!

Примечание: этот трюк зависит от вызова компонентаWillMount(), прежде чем NavigationBarRouteMapper будет работать. Если это изменение в будущем, это, безусловно, сломает его. Но теперь он работает безупречно!

'use strict'; 

import React, {Component} from 'react'; 
import ReactNative from 'react-native'; 

const { 
    AppRegistry, 
    StyleSheet, 
    Text, 
    View, 
    Navigator, 
    Alert, 
    TouchableHighlight 
} = ReactNative; 

class Home extends Component { 

    //This trick depends on that componentWillMount fires before the navbar is created 
    componentWillMount() { 
     this.props.route.navbarTitle = "Home"; 

     this.props.route.rightNavButton = { 
      text: "Button", 
      onPress: this._doSomething.bind(this) 
     }; 
    } 

    _doSomething() { 
    Alert.alert(
     'Awesome, eh?', 
     null, 
     [ 
     {text: 'Indeed'}, 
     ] 
    ) 
    } 

    render() { 
    return (
     <View style={styles.container}> 
      <Text>You are home</Text> 
     </View> 
    ); 
    } 
} 

class AppContainer extends Component { 

    renderScene(route, navigator) { 
     switch(route.name) { 
      case "Home": 
     //You must pass route as a prop for this trick to work properly 
      return <Home route={route} navigator={navigator} {...route.passProps} /> 
      default: 
      return (
     <Text route={route} 
     style={styles.container}> 
      Your route name is probably incorrect {JSON.stringify(route)} 
      </Text> 
    ); 
     } 
    } 

    render() { 
    return (
     <Navigator 
     navigationBar={ 
      <Navigator.NavigationBar 
      style={ styles.navbar } 
      routeMapper={ NavigationBarRouteMapper } /> 
     } 

     initialRoute={{ name: 'Home' }} 
     renderScene={ this.renderScene } 

     /> 
    ); 
    } 
} 

//Nothing fancy here, except for checking for injected buttons. 
var NavigationBarRouteMapper = { 
    LeftButton(route, navigator, index, navState) { 
    if(route.leftNavButton) { 
     return (
     <TouchableHighlight 
     style={styles.leftNavButton} 
     underlayColor="transparent" 
     onPress={route.leftNavButton.onPress}> 
      <Text style={styles.navbarButtonText}>{route.leftNavButton.text}</Text> 
     </TouchableHighlight> 
    ); 
    } 
    else if(route.enableBackButton) { 
     return (
     <TouchableHighlight 
     style={styles.leftNavButton} 
     underlayColor="transparent" 
     onPress={() => navigator.pop() }> 
      <Text style={styles.navbarButtonText}>Back</Text> 
     </TouchableHighlight> 
    ); 
    } 
    }, 
    RightButton(route, navigator, index, navState) { 
    if(route.rightNavButton) { 
     return (
     <TouchableHighlight 
     style={styles.rightNavButton} 
     underlayColor="transparent" 
     onPress={route.rightNavButton.onPress}> 
      <Text style={styles.navbarButtonText}>{route.rightNavButton.text}</Text> 
     </TouchableHighlight> 
    ); 
    } 
    }, 
    Title(route, navigator, index, navState) { 
    return (<Text style={styles.navbarTitle}>{route.navbarTitle || route.name}</Text>); 
    } 
}; 

var styles = StyleSheet.create({ 
    container: { 
    flex: 1, 
    justifyContent: 'center', 
    alignItems: 'center', 
    backgroundColor: '#F5FCFF', 
    marginTop: 66 
    }, 
    navbar: { 
    backgroundColor: '#ffffff', 
    }, 
    navbarTitle: { 
    marginVertical: 10, 
    fontSize: 17 
    }, 
    leftNavButton: { 
    marginVertical: 10, 
    paddingLeft: 8, 
}, 
    rightNavButton: { 
    marginVertical: 10, 
    paddingRight: 8, 
    }, 
    navbarButtonText: { 
    fontSize: 17, 
    color: "#007AFF" 
    } 
}); 

AppRegistry.registerComponent('AppContainer',() => AppContainer); 
+0

Отличное решение !! Некоторое время боролся с этим. Большое спасибо за подсказку! Как бы вы назначили начальную кнопку? Вы вводите кнопки на сцену, но я бы хотел назначить кнопку «Меню» из корня. – funkysoul

+0

@funkysoulzh В правильном методе внутри NavigationBarRouteMapper, например LeftButton, добавьте предложение if-condition и добавьте в него кнопку. Точно так же, как я добавляю кнопку «Назад» в методе LeftButton. Но в вашем случае вы можете проверить имя маршрута. –

+0

Эй, Ахмед, я понял, что моя логика кривая, поскольку я начинаю с начальной сцены, я также могу прикрепить «начальные» кнопки к этой сцене. Когда вы сидите перед чем-то слишком долго, вы вдруг не видите, как легко это ;-). В любом случае спасибо за вышесказанное! – funkysoul