2016-12-02 9 views
5

Mam niestandardowy widok natywny w ramach projektu Ignite. Próbuję skonfigurować komunikację od Objective-C do React Native. Komunikacja z React Native do iOS działa z wtryskiem HTML, ale nie na odwrót. Próbowałem używać zarówno RCTBubblingEventBlock i RCTDirectEventBlock, ale nie działają. Oto cała moja implementacja. Zmieniłem nazwy składników oczywiście, i tylko w lewo zasadniczą wdrożenia dla zrozumienia tego, co zostało zrobione do tej pory:Reaguj Natywne składniki interfejsu użytkownika: RCTBubblingEventBlock/RCTDirectEventBlock nie działają.

Objective-C kodu:

// CustomViewManager.h 

#import "RCTViewManager.h" 

@interface CustomViewManager : RCTViewManager 

@end 


// CustomViewManager.m 

#import "CustomViewManager.h" 
#import "CustomView.h" 

#import "RCTBridge.h" 
#import "RCTEventDispatcher.h" 
#import "UIView+React.h" 

@implementation CustomViewManager 

RCT_EXPORT_MODULE() 
RCT_EXPORT_VIEW_PROPERTY(htmlInjection, NSString) 
RCT_EXPORT_VIEW_PROPERTY(onEventA, RCTDirectEventBlock) 
RCT_EXPORT_VIEW_PROPERTY(onEventB, RCTDirectEventBlock) 

- (UIView *) view { 
    return [CustomView new]; 
} 

@end 

// CustomView.h 

#import "RCTView.h" 

@interface CustomView : RCTView 

@property (nonatomic, assign) NSString *htmlInjection; 
@property (nonatomic, copy) RCTDirectEventBlock onEventA; 
@property (nonatomic, copy) RCTDirectEventBlock onEventB; 

@end 

// CustomView.m 

#import "CustomView.h" 
#import "RCTUtils.h" 

#import "RCTBridge.h" 
#import "RCTEventDispatcher.h" 
#import "UIView+React.h" 
#import "MyExternalComponent.h" 

@interface CustomView() <UIWebViewDelegate> 
@property (nonatomic, strong) UIWebView* webView; 

@end 


- (void) setUpWebView { 
    if (!_webView) { 
    [self setWebView: [UIWebView new]]; 
    _webView.delegate = self; 
    [self addSubview:_webView]; 
    } 
} 

- (instancetype)init 
{ 
    self = [super init]; 
    [self setUpWebView]; 
    return self; 
} 

- (id)initWithFrame:(CGRect)frame 
{ 
    self = [super initWithFrame:frame]; 
    if (self) { 
    [self setUpWebView]; 
    } 
    return self; 
} 

- (id)initWithCoder:(NSCoder *)aDecoder { 
    if ((self = [super initWithCoder:aDecoder])) { 
    [self setUpWebView]; 
    } 
    return self; 
} 

- (void) layoutSubviews { 
    [super layoutSubviews]; 
    CGRect frame = self.frame; 
    self.webView.frame = frame; 
} 

#pragma mark - External methods. 

- (void) setHtmlInjection:(NSString *)html { 
    [_webView loadHTMLString:html baseURL:nil]; 
} 

#pragma mark - Non-React component methods. 

- (void) fetchData { 
    [MyExternalComponent getData:^(NSString *dataA, NSError *error){ 
      if(error) { 
       NSLog(@"Here be errors: %@", error); 
       _onEventB(@{@"myError": error.localizedDescription}); 
      } else { 
       _onEventA(@{@"myData": dataA}); 
      } 
     }] 
} 

@end 

React NativeJavaScript kod:

// MyCustomView.js 

import React from 'react'; 
import { requireNativeComponent } from 'react-native'; 

class MyCustomView extends React.Component { 
    constructor(props) { 
    super(props); 
    this._onEventA= this._onEventA.bind(this); 
    this._onEventB= this._onEventB.bind(this); 
    } 
    _onEventA(event: Event) { 
    if (!this.props.onEventA) { 
     return; 
    } 
    this.props.onEventA(event.nativeEvent.myData); 
    } 
    _onEventB(event: Event) { 
    if (!this.props.onEventA) { 
     return; 
    } 
    this.props._onEventB(event.nativeEvent.myError); 
    } 
    render() { 
    return (
     <CustomView 
     {...this.props} 
     onEventA={this._onEventA} 
     onEventB={this._onEventB} 
     /> 
    ); 
    } 
} 

MyCustomView.propTypes = { 
    htmlInjection: React.PropTypes.string, 
    onEventA: React.PropTypes.func, 
    onEventB: React.PropTypes.func, 
}; 

var CustomView = requireNativeComponent('CustomView', MyCustomView); 

module.exports = MyCustomView; 

// CustomWrapperContainer.js 

class CustomWrapperContainer extends React.Component { 

    api: Object; 
    constructor (props: Object) { 
    super(props); 
    this.state = { 
     htmlInjection: '', 
     myDataA: 'Some placeholder text' 
    }; 

    this.api = RestApi.create(); 
    } 

    render() { 
    return (
     <View style={styles.container}> 
     <KeyboardAvoidingView behavior='position'> 
      <Text>{this.state.myDataA}</Text> 
      <MyCustomView 
      style={styles.myStyle} 
      htmlInjection={this.state.htmlInjection} 
      onEventA={this.handleEventA.bind(this)} 
      onEventB={this.handleEventB.bind(this)} 
      /> 
     </KeyboardAvoidingView> 
     </View> 
    ) 
    } 

    handleEventA = (data) => { 
    console.log('on Event A', data); 
    this.setState({myDataA: data}) 
    }; 

    handleEventB = (error) => { 
    console.log('On Event B', error); 
    }; 
} 

const mapStateToProps = (state) => { 
    return { 
    } 
} 

const mapDispatchToProps = (dispatch) => { 
    return { 
    } 
} 

export default connect(mapStateToProps, mapDispatchToProps)(CustomWrapperContainer) 

Śledziłem numer example od React Native, a także kilka innych, ale dotychczas nie miałem szczęścia w uzyskaniu wydarzenia od iOS do React Native. Nie mogłem również znaleźć istotnej pomocy w tej sprawie z istniejących artykułów.

używa react wersja 15.3.2. Być może to jest problem? A może wersja jakiejś innej zależności? Nie jestem pewny. Byłbym bardzo wdzięczny za pomoc lub wskazówki.

P.S .: Uruchomiłem to na obu urządzeniach i symulatorach z iOS 9.2 do 10.0 i nie widzę żadnych zmian w zachowaniu, więc to nie jest problem.

+0

pierwszą rzeczą, myślę o tym, kiedy widząc to, to upewnij się, że za trudny V2 RNWebview mostu. To będzie lądowanie w RN Master wkrótce: https://github.com/alinz/react-native-webview-bridge/tree/v2 – GantMan

+0

Dzięki. Ale nie rozumiem, jak to jest związane z problemem, który mam. Mam webView, w którym ładuję zawartość HTML i która działa dobrze. Dopiero gdy próbuję przekazać dane za pośrednictwem wywołań zwrotnych, komunikacja nie działa. –

+0

Tak, przykro mi, że nie widziałem nic złego w tym kodzie, więc miałem nadzieję dostarczyć dodatkowych informacji. Czy masz ten kod na repozytorium, do którego mogę uzyskać dostęp? – GantMan

Odpowiedz

1

W porządku, biorąc pod uwagę, że RCTBubblingEventBlock i RCTDirectEventBlock wydają się być uszkodzone, musiałem znaleźć inne podejście do przekazywania wywołań zwrotnych w kodzie JS. Odkryłem więc, że podejście przyjęte dla emulatorów zdarzeń zdawało się być obiecujące i stwierdziłem, że iOS ma obiekt, którego mógłbym użyć.

Po wielu zabawach i rozglądaniu się, znalazłem ten gist, który pomógł mi zbudować moją komunikację od iOS do JS. Nie czuć się czysto i było o wiele więcej kodu do napisania, żeby go skonfigurować, ale zadziałało na końcu. Mam nadzieję, że tak pozostanie.

Mam również nadzieję, że zalecana metoda użycia RCTBubblingEventBlock i RCTDirectEventBlock działa w pewnym momencie!

+1

wow! Dzięki za zbadanie i odkrycie! Nie mam pojęcia. – GantMan

1

Ta odpowiedź może się spóźnić, ale mam nadzieję, że to pomogłoby.

Po pierwsze dziękuję za twoje badania. Też utknąłem w tym samym problemie co twój, a potem musiałem użyć RCTEventEmitter jako odpowiedzi.

Ale później dwukrotnie sprawdziłem i przejrzałem mój kod, znalazłem kilka punktów, które pomagają w poprawnym działaniu mojego kodu z RCTBubblingEventBlock.

Widziałem, że używasz

MyCustomView.propTypes = { 
    htmlInjection: React.PropTypes.string, 
    onEventA: React.PropTypes.func, 
    onEventB: React.PropTypes.func, 

i

<CustomView 
     {...this.props} 
     onEventA={this._onEventA} 
     onEventB={this._onEventB} 
     /> 

blok {...} this.props ustawi wszystkie rekwizyty MyCustomView do CustomView. W innym widoku, jeśli skonfigurowane są opcje onEventA i onEventB of MyCustomView, wówczas onEventA i onEventB z CustomView będą miały tę samą wartość z powodu {... this.props}.

spróbować usunąć ten w nieruchomości zdefiniować kod MyCustomView

onEventA: React.PropTypes.func, 
onEventB: React.PropTypes.func, 

Albo można użyć właściwości konfiguracyjne dla natywnego jedynie kodu w React rodzimy przykład MapView

const RCTMap = requireNativeComponent('RCTMap', MapView, { 
    nativeOnly: { 
    onAnnotationDragStateChange: true, 
    onAnnotationFocus: true, 
    onAnnotationBlur: true, 
    onChange: true, 
    onPress: true 
    } 
}); 
+0

Dzięki @khanhha! To rozwiązanie wydaje się obiecujące. Chciałbym, żebyś przyszedł miesiąc temu, byłoby to bardzo pomocne. Ale jestem pewien, że to rozwiązanie przyda mi się również w przyszłości. :) –

0

wpadłem na inny wydać z RCTBubblingEventBlock. Wszystkie RCTBubblingEventBlock muszą być poprzedzone prefiksem on. Obecnie nie jest to odnotowane w dokumentacji.

Na przykład:

onMyEvent //will work 
myEvent //no good 
Powiązane problemy