2016-12-02 20 views
5

Tôi có chế độ xem gốc tùy chỉnh trong một dự án Ignite. Tôi đang cố gắng thiết lập một liên lạc từ Objective-C đến React Native. Giao tiếp từ React Native đến iOS hoạt động với tiêm HTML, nhưng không phải là cách khác. Tôi đã thử sử dụng cả hai RCTBubblingEventBlockRCTDirectEventBlock, nhưng không hoạt động. Đây là toàn bộ việc triển khai của tôi. Tôi đã thay đổi tên của các thành phần của khóa học, và chỉ còn lại thực hiện rất cần thiết cho sự hiểu biết của bạn về những gì đã được thực hiện cho đến nay:Các thành phần UI gốc phản ứng: RCTBubblingEventBlock/RCTDirectEventBlock dường như không hoạt động

Objective-C mã:

// 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 mã:

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

Tôi đã theo dõi example từ chính bản thân số React Native và một số thứ khác, nhưng tôi đã không có may mắn cho đến nay khi nhận được sự kiện để vượt qua từ iOS đến React Native. Tôi đã không thể tìm thấy sự trợ giúp đáng kể trong vấn đề này từ các bài viết hiện có.

Ignite sử dụng react phiên bản 15.3.2. Có lẽ đó là vấn đề? Hoặc phiên bản của một số phụ thuộc khác ở đó? Tôi không chắc. Tôi rất cảm kích sự giúp đỡ hay dẫn dắt.

P .: Tôi đã chạy nó trên cả hai thiết bị và mô phỏng chạy iOS 9.2 thông qua 10.0 và tôi không thấy bất kỳ thay đổi nào về hành vi, vì vậy đó không phải là vấn đề.

+0

điều đầu tiên tôi nghĩ đến khi nhìn thấy điều này, là hãy chắc chắn để xem xét thử v2 cầu RNWebview. Việc này sẽ sớm được đưa vào RN Master: https://github.com/alinz/react-native-webview-bridge/tree/v2 – GantMan

+0

Cảm ơn bạn. Nhưng tôi không hiểu làm thế nào điều này liên quan đến vấn đề tôi đang gặp phải. Tôi có một webView mà tôi tải nội dung HTML và nó hoạt động tốt. Chỉ khi tôi cố gắng trả lại dữ liệu qua các cuộc gọi lại thì giao tiếp không hoạt động. –

+0

Vâng, xin lỗi tôi đã không thấy bất cứ điều gì sai với mã này vì vậy tôi đã hy vọng sẽ cung cấp một số thông tin bổ sung. Bạn có mã này trong một repo tôi có thể truy cập? – GantMan

Trả lời

1

Được rồi, do đó, cho rằng RCTBubblingEventBlockRCTDirectEventBlock dường như bị hỏng, tôi phải tìm cách tiếp cận khác để chuyển số gọi lại vào mã JS. Vì vậy, tôi thấy rằng cách tiếp cận được thực hiện cho Android với bộ phát sự kiện có vẻ đầy hứa hẹn và tôi đã tìm thấy rằng iOS có một đối tượng RCTEventEmitter mà tôi có thể sử dụng.

Sau nhiều lần chơi/nhìn xung quanh, tôi tìm thấy số này gist giúp tôi xây dựng liên lạc của mình từ iOS đến JS. Nó không cảm thấy sạch sẽ, và có rất nhiều mã để viết để có được nó thiết lập, nhưng nó làm việc cuối cùng. Tôi hy vọng nó vẫn như vậy.

Tôi cũng hy vọng rằng phương pháp được đề xuất sử dụng RCTBubblingEventBlockRCTDirectEventBlock hoạt động tại một số điểm!

+1

wow! Cảm ơn bạn đã nghiên cứu và khám phá điều này! Tôi không ý kiến. – GantMan

1

Câu trả lời này có thể đến trễ, nhưng tôi hy vọng điều đó sẽ hữu ích.

Trước hết cảm ơn bạn đã nghiên cứu. Tôi cũng mắc kẹt trong cùng một vấn đề như của bạn và sau đó tôi đã phải sử dụng RCTEventEmitter như câu trả lời của bạn.

Nhưng sau đó tôi kiểm tra lại và xem lại mã của mình, tôi đã tìm thấy một số điểm giúp mã của tôi chạy tốt với RCTBubblingEventBlock.

tôi thấy rằng bạn sử dụng

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

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

Khối {...} this.props sẽ đặt tất cả các đạo cụ của MyCustomView để CustomView. Trong một khung nhìn khác nếu onEventA và onEventB của MyCustomView được cấu hình thì onEventA và onEventB của CustomView sẽ có cùng giá trị vì {... this.props}.

Cố gắng loại bỏ điều này trong bất động sản xác định quy tắc ứng MyCustomView

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

Hoặc bạn có thể sử dụng thuộc tính cấu hình cho mã chỉ có nguồn gốc trong Phản ứng bản địa ví dụ MapView

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

Cảm ơn @khanhha! Giải pháp đó có vẻ đầy hứa hẹn. Tôi ước bạn sẽ đi cùng một tháng trước, nó sẽ thực sự hữu ích. Nhưng tôi chắc rằng giải pháp này sẽ hữu ích cho tôi trong tương lai. :) –

0

tôi chạy vào một khác nhau vấn đề với RCTBubblingEventBlock. Tất cả RCTBubblingEventBlock phải được bắt đầu bằng on. Điều này hiện không được ghi nhận trong tài liệu.

Ví dụ:

onMyEvent //will work 
myEvent //no good 
Các vấn đề liên quan