Markku
Markku

Reputation: 565

How to pass a component reference to onPress callback?

I did render following kind of list with onPress "handler".

enter image description here

I have realised that onPress handler is useless because I cannot get the reference of race pressed. I get ref is not defined error.

var races = Engine.possibleRaces;

function racePressed(ref) {
    console.log("REF: " + ref); // is never called
}

var races = Engine.possibleRaces;
var rowViews = [];
for (var i = 0; i < races.length; i++) {
  rowViews.push(
    <Text
      ref={i}
      onPress={() => racePressed(ref)} // ref is not defined
      style={styles.raceText}>{races[i].text}
    </Text>

  );
}

<View style={{width: Screen.width, flexDirection:'row', flexWrap: 'wrap', alignItems: "center"}}>
       {rowViews}
</View>  

I did also try to pass i as a parameter. It did not work, because it has the value after iteration ends. Basically it has races.length value.

  onPress={() => racePressed(i)} // Same as races.length

Edit:

I did isolate problem to following program.

'use strict';
import React, {
  AppRegistry,
  Component,
  StyleSheet,
  Text,
  View
} from 'react-native';

let texts = [{text: "Click wrapper text1"}, {text: "Click wrapper text2"}];

class sandbox extends Component {

  rowPressed(ref, i) {
    console.log("rowPressed: " + ref + " " + i)
  }

  render() {

    var rows = [];

    for (var i = 0; i < texts.length; i++) {
      rows.push(
        <Text
          ref={i}
          onPress={() => this.rowPressed.bind(this, i)}
          style={styles.raceText}>{texts[i].text}
        </Text>
      );
    }

    return (
      <View style={styles.container}>

        <View>
          {rows}
        </View>

      </View>
    );
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center'
  }
});

AppRegistry.registerComponent('sandbox', () => sandbox);

Callback is not called and no errors thrown except following warning

[tid:com.facebook.React.JavaScript] Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of `sandbox`. See https://fb.me/react-warning-keys for more information.

Upvotes: 7

Views: 22895

Answers (2)

Adrian Seungjin Lee
Adrian Seungjin Lee

Reputation: 1666

I suggest you bind that function in constructor like..

constructor(props){
    super(props);
    //your codes ....

    this.rowPressed = this.rowPressed.bind(this);
}

This binds this context of rowPressed function as you expect it to be, making your code works properly.

Also, to get rid of warning messages you should provide unique key properties for each <Text> element, using <Text key={i} ....> in your code should work.

Upvotes: 12

cdcl
cdcl

Reputation: 69

I try to do something similar and found this solution :

render() {
    var _data = texts;
    return (
        <View style={styles.container}>
        { _data.map(function(object,i) {
            return (
                <Text ref={i}
                  onPress={() => this.rowPressed(i)}
                  style={styles.raceText}>{texts[i].text}
                </Text> );
            })
        }
        </View>
    );
}

Cheers

Upvotes: 3

Related Questions