Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Query for child components [JS -> ObjC binding] #126

Closed
jaygarcia opened this issue Mar 5, 2015 · 12 comments
Closed

Query for child components [JS -> ObjC binding] #126

jaygarcia opened this issue Mar 5, 2015 · 12 comments
Labels
Resolution: Locked This issue was locked by the bot.

Comments

@jaygarcia
Copy link
Contributor

If I wanted to get a reference to the underlying Component for a Touchable child, how does one do this?

<TouchableHighlight underlayColor="rgb(210, 230, 255)" onPress={this.onPress}>
    <Text>ClickMe</Text>
</TouchableHighlight>

I've read
http://facebook.github.io/react/tips/communicate-between-components.html

... but it very much speaks to the data that represents the div, not the div itself.

How do i get a reference to the actual JavaScript -> ObjC binding node for the Text element above in this.onPress?

@jaygarcia jaygarcia changed the title Query for child components Query for child components [JS -> ObjC binding] Mar 5, 2015
@vjeux
Copy link
Contributor

vjeux commented Mar 5, 2015

What is your end goal?

To your question, the facility with React is called ref. But in this case I have a feeling that it's not the solution you are looking for. http://facebook.github.io/react/docs/more-about-refs.html

this.refs[refKey].getNodeHandle()

@jaygarcia
Copy link
Contributor Author

Background:
I'm building a React Native Videogame music player as a demo application.

I'd like to be able to do things like disable/enable the rendering of Audio waveforms via tap of the waveform view instance. Rather than destroy the waveform view when tapped, i'd rather set a boolean that stops the waveform from rendering.

My thoughts is to bind a onPress event inside of the ReactJS implementation of the custom UI view, but UIView doesn't respond to taps natively. So, the only way to listen to taps using the React iOS API is to wrap my custom view w/ a Touchable component.

I can setup onPress via Touchable, but I need to somehow get a reference to the child that Touchable is wrapping to disable the rendering of the waveform.

Now, I could listen for tap events on the custom waveform UI view, but that feels like cheating :(

@vjeux
Copy link
Contributor

vjeux commented Mar 5, 2015

Oh I see, you want to integrate with an Obj-c component. Then yeah, ref and getNodeHandle() is the right way to do it.

@sahrens
Copy link
Contributor

sahrens commented Mar 7, 2015

If you're just enabling disabling, you should do it with a prop:
<TouchableHighlight onPress={()=>this.setState({enabled: !this.state.enabled})}>

Then map the enabled prop through to your native view, and run whatever native code you want in the setEnabled: setter. Maybe take a look at RCTNetworkImageView(Manager).m

-Spencer

On Mar 5, 2015, at 12:37 PM, Christopher Chedeau notifications@github.com wrote:

Oh I see, you want to integrate with an Obj-c component. Then yeah, ref and getNodeHandle() is the right way to do it.


Reply to this email directly or view it on GitHub.

@jaygarcia
Copy link
Contributor Author

RCTNetworkImageView no longer has a manager, from what I can tell.

What i'm trying to achieve:

From the context of whatever class is the result of React.createClass(), where the render function returns below:

        return (
            <View style={styles.container}>
                <View style={styles.titleBar}>
                    <Text style={{fontSize: 20}}>{gameObj.game}</Text>
                </View>

                <ScrollView horizontal={true} style={styles.imageContainer} pagingEnabled={true} centerContent={true}>
                    {images}
                </ScrollView>

                <View style={styles.vizContainer}>
                    <RCEzAudioPlotGlView style={styles.vizItem}/>
                    <RCEzAudioPlotGlView style={styles.vizItem}/>
                </View>

                <View style={styles.controlsContainer}>
                    <Text style={styles.timeText}>
                        Current Time : {state.currentTime}
                    </Text>
                    <Text style={styles.trackText}>
                        {state.currentTrack + 1}  of {gameObj.trackCount + 1}
                    </Text>
                    <ControlButton onPress={this.onButtonPress} btnChar={"prev"} btnStyle={"prevButton"}/>
                    <ControlButton onPress={this.onButtonPress} btnChar={centerBtnChar} btnStyle={centerBtnStyle}/>
                    <ControlButton onPress={this.onButtonPress} btnChar={"next"} btnStyle={"nextButton"}/>
                </View>                     
            </View>
        );

I'd like to gain access to the RCEzAudioPlotGlView instances and send an array of floating points to them to render sound waves.

Now, I've /kinda/ gotten a foothold of them via the following really ugly code.
---side note, i've tried to use getNativeNode() or getNodeHandle() and those seem to return integers, which confuses me :P

    onButtonPress : function(buttonType) {
        // var o = this._renderedComponent._renderedChildren['.3']._renderedChildren['.2'];
        var viewContainer = this._reactInternalInstance._renderedComponent._renderedComponent._renderedChildren['.2'],
            children      = viewContainer._renderedComponent._renderedChildren,
            leftViz       = children['.0'],
            rightViz      = children['.1'];

        leftViz._instance.something()
        debugger;
        var methodName = this.methodMap[buttonType];
        this[methodName] && this[methodName]();
    },

the leftViz & rightViz JS references basically put me within the context of the module in which i've defined RCEzPlotGlView (below).

var View = React.createClass({
    statics : {
        pointerEvents: StyleConstants.PointerEventsValues,
        stylePropType
    },

    mixins: [NativeMethodsMixin],

    /**
    * `NativeMethodsMixin` will look for this when invoking `setNativeProps`. We
    * make `this` look like an actual native component class.
    */
    viewConfig: {
        uiViewClassName: 'RCEzPlotGlView',
        validAttributes: ReactIOSViewAttributes.RKView
    },

    render: function() {
        return <RCEzPlotGlView {...this.props} />;
    },
    something : function() {
        console.log('stopped')
        debugger;
    }
});

var RCEzPlotGlView = createReactIOSNativeComponentClass({
    validAttributes: ReactIOSViewAttributes.RKView,
    uiViewClassName: 'RCEzPlotGlView',
});

What i'm missing is how to get from the ReactJS class to Objective C land for that particular instance. Inspecting this.refs results in an empty object.

refs

@jaygarcia
Copy link
Contributor Author

I believe that I've gotten a step closer by inspecting the RCStaticImageManager.m source:

I suppose I was looking for directly calling functions like with what the RC_EXPORT() macro does for managers.

The RCT_CUSTOM_VIEW_PROPERTY macro seems to be the right way to go a la the example below:

RCT_CUSTOM_VIEW_PROPERTY(imageTag, RCTStaticImage *)
{
  if (json) {
    [RCTImageLoader loadImageWithTag:[RCTConvert NSString:json] callback:^(NSError *error, UIImage *image) {
      if (error) {
        RCTLogWarn(@"%@", error.localizedDescription);
      } else {
        view.image = image;
      }
    }];
  } else {
    view.image = defaultView.image;
  }
}

@sahrens
Copy link
Contributor

sahrens commented Mar 14, 2015

Yes, you should just use props when possible.

The handles are meant to be opaque references so the value/contents should be irrelevant from a JS perspective. You can pass them over the bridge to native and native can use them to find the corresponding native element. One example where this is done is the scrollTo method on RCTScrollViewManager.

-Spencer

On Mar 14, 2015, at 10:31 AM, Jay Garcia notifications@github.com wrote:

I believe that I've gotten a step closer by inspecting the RCStaticImageManager.m source:

I suppose I was looking for directly calling functions like with what the RC_EXPORT() macro does for managers.

The RCT_CUSTOM_VIEW_PROPERTY macro seems to be the right way to go a la the example below:

RCT_CUSTOM_VIEW_PROPERTY(imageTag, RCTStaticImage *)
{
if (json) {
[RCTImageLoader loadImageWithTag:[RCTConvert NSString:json] callback:^(NSError *error, UIImage *image) {
if (error) {
RCTLogWarn(@"%@", error.localizedDescription);
} else {
view.image = image;
}
}];
} else {
view.image = defaultView.image;
}
}

Reply to this email directly or view it on GitHub.

@jaygarcia
Copy link
Contributor Author

Thanks @sahrens. I've gotten tot he point where a view Mgr can execute methods on view instances.

Now it's time to see how well this thing deals with 512 floating point audio samples =) per channel at 30fps.

@sahrens
Copy link
Contributor

sahrens commented Mar 14, 2015

If you batch it up, I bet it won't be a problem :)

-Spencer

On Mar 14, 2015, at 11:34 AM, Jay Garcia notifications@github.com wrote:

Thanks @sahrens. I've gotten tot he point where a view Mgr can execute methods on view instances.

Now it's time to see how well this thing deals with 512 floating point audio samples =) per channel at 30fps.


Reply to this email directly or view it on GitHub.

@jaygarcia
Copy link
Contributor Author

... slowly ... but ... surely ...
(This is just random data)

2015-03-14_19-45-57

@jaygarcia
Copy link
Contributor Author

Getting a lot closer. Timing needs to be adjusted. Seems that making the round trip from objc -> JS -> objc of 1024 floats was way too slow. Now the visualizers actually query the singleton themselves for the buffer data so it's objc -> objc and lighting fast.

http://youtu.be/lTqo0iAQ4Gc

@jaygarcia
Copy link
Contributor Author

I'm going to close this thread. The only thing I'm going to add before I close it is that this really needs to be documented =). I've gotten things to work but it's hard for me to know if what i've implemented are hacks or the right patterns. :P

@facebook facebook locked as resolved and limited conversation to collaborators May 29, 2018
@react-native-bot react-native-bot added the Resolution: Locked This issue was locked by the bot. label Jul 23, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
Resolution: Locked This issue was locked by the bot.
Projects
None yet
Development

No branches or pull requests

4 participants