10

I am just learning React Native and I want to create a series of buttons using dynamic data. My current code is:

var locations = this.state.campus.map(function(item, key){
            return(
                <TouchableHighlight key={key}
                style={[styles.button, (this.state.location==={item} && styles.buttonPressed)]}
                underlayColor='#dddddd'
                onPress={()=>this.buttonPress({item})} >
               <Text style={
                   styles.plainText}>{item}</Text>
            </TouchableHighlight>
           )

My issue is with the lines

style={[styles.button, (this.state.location==={item} && styles.buttonPressed)]}

and

onPress={()=>this.buttonPress({item})}

I am trying generate these lines using the data dynamically off the map function. These lines of code work perfectly if I use static data (ie generate each button separately), but fail using dynamic data. The code does produce a display so the issue is not with rendering, the issue is with the functionality.

With the button press I get the error message undefined in not an object while the style simply causes the whole display not to render.

It is obvious that the dynamic data ({item}) works inside the Text element but not when passed to the other two elements as data. I have tried using {{item}} but this throws a syntax error.

Is there a way to handle dynamic data like this in React Native?

Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
nwilliams36
  • 191
  • 1
  • 1
  • 10
  • For someone in the future...the solution provided here might help: http://stackoverflow.com/questions/35663375/how-to-pass-a-component-reference-to-onpress-callback – Sunny Patel Jan 05 '17 at 17:18
  • the issue is happened because you are usin function(item, key){ and you have to use arrow function var locations = this.state.campus.map((item, key) => { return – Anja Ishmukhametova Jan 06 '17 at 07:57

4 Answers4

10

In both cases you are unnecessarily wrapping item in {}. For both of these lines, the expressions inside the outer {} are pure javascript (an array and a function) and should follow javascript syntax.

So the lines should read as follows:

style={[styles.button, (this.state.location===item && styles.buttonPressed)]}

and

onPress={()=>this.buttonPress(item)}
Joe P
  • 444
  • 2
  • 5
  • You are probably correct, however this does not solve the issue, it just creates more errors. I now think my whole design is wrong so I will go back to the drawing board and work out how to do this a different way. I think I need to create these buttons in a ListView. – nwilliams36 Jul 22 '15 at 23:10
  • You should [always avoid using either `bind` or arrow functions inside JSX/inside the `render` function](https://stackoverflow.com/questions/36677733/why-shouldnt-jsx-props-use-arrow-functions-or-bind) because they create a new function every time which causes every item in the list/array/map to be re-rendered when a single one is pressed unless you also provide a custom comparison function in `shouldComponentUpdate` that skips comparing the `buttonPress` field. – hippietrail Sep 26 '17 at 04:13
0

You should store this in another variable : let _this =this;

Then use _this instead of this

August
  • 9
  • 1
0

the issue is happened because you are using function(item, key){ and you have to use arrow function

let locations = this.state.campus.map((item, key) => { return <TouchableHighlight key={key}..   

you have to do it for keep using 'this' context

Anja Ishmukhametova
  • 1,535
  • 16
  • 14
-2

This method is work: 1) Create function for creating elements with dynamic datas

createElement = (item) => {
    return(
        <TouchableHighlight onPress={()=>this.buttonPress({item})}>
            <Text style={ styles.plainText }> {item} </Text>
        </TouchableHighlight>
    )
};

2) Use this function into render function how in follow example:

render (
    elementsList = [];
    for (var i = 0; i < 10; i++){
        elementsList.push( this.createElement(i) );
    };

    return (
        <View>
            {elementsList}
        </View>
    )
);

It work, if you understand how use this.