87

Is it possible to loop an identical component in Render function?

Something like this:

... onPress = () => { ... }; initialArr = [["blue","text1"],["red","text2"]]; buttonsListArr = []; for (let i = 0; i < initialArr.length; i++) { buttonsListArr.push( <Button style={{borderColor:{initialArr[i][0]}}} onPress={this.onPress.bind(this)}>{initialArr[i][1]}</Button> ); } ... render() { return ( <View style={...}> {buttonsListArr} </View> )}; 

I mean this is just finite list of components, so any components like ListView/ScrollView etc is not applicable in this particular case. This is just syntax question.

2
  • why dont you use map instead? const buttons = buttonsListArr.map( item => <Button style={{borderColor:item[0]}} onPress={this.onPress.bind(this)}>{item[1]}</Button> render() { return ( <View style={...}> <buttons /> </View> )}; Commented Mar 1, 2017 at 3:28
  • I understand that map works very well here, but I'm curious as to exactly why pushing into an array didn't work. Commented Aug 22, 2022 at 23:29

4 Answers 4

77

You would usually use map for that kind of thing.

buttonsListArr = initialArr.map(buttonInfo => ( <Button ... key={buttonInfo[0]}>{buttonInfo[1]}</Button> ); 

(key is a necessary prop whenever you do mapping in React. The key needs to be a unique identifier for the generated component)

As a side, I would use an object instead of an array. I find it looks nicer:

initialArr = [ { id: 1, color: "blue", text: "text1" }, { id: 2, color: "red", text: "text2" }, ]; buttonsListArr = initialArr.map(buttonInfo => ( <Button ... key={buttonInfo.id}>{buttonInfo.text}</Button> ); 
Sign up to request clarification or add additional context in comments.

3 Comments

Thanks for this answer. Can you explain why map is used? I was trying forEach and that didn't work. I'm confused as to why I must use map.
@AlexWang you use map because for each simply iterates through the elements while map returns an array of the same size, filled with the results of the mapping function.
react-like renders are based on returns, forEach doesn't return anything (from inside) though, so not suitable for return-based-rendering loop right :-) However if you don't want to render and just log data/send them away (basically anything else than return), then forEach((el, i) =>... would make more sense semantically :)
59
render() { return ( <View style={...}> {initialArr.map((prop, key) => { return ( <Button style={{borderColor: prop[0]}} key={key}>{prop[1]}</Button> ); })} </View> ) } 

should do the trick

3 Comments

Looks good, but I would move the mapping to before the return statement to make things look nicer and just use the mapped array variable name inside the View. As a note, the second parameter to the map function is the index of the element in the array you are going through. Though they might be a different integer every time, they might not necessarily be good candidates for the key property. The array elements could change and so the key would have to be changed as well (if you used an unique identifier, the keys would remain the same even though the indices have changed).
According to the React docs, "We don't recommend using indexes for keys if the items can reorder, as that would be slow. " -- facebook.github.io/react/docs/lists-and-keys.html (Keys section, bottom)
@nbkhope thats new information for me about the keys. Thanks!
27

For initial array, better use object instead of array, as then you won't be worrying about the indexes and it will be much more clear what is what:

const initialArr = [{ color: "blue", text: "text1" }, { color: "red", text: "text2" }]; 

For actual mapping, use JS Array map instead of for loop - for loop should be used in cases when there's no actual array defined, like displaying something a certain number of times:

onPress = () => { ... }; renderButtons() { return initialArr.map((item) => { return ( <Button style={{ borderColor: item.color }} onPress={this.onPress} > {item.text} </Button> ); }); } ... render() { return ( <View style={...}> { this.renderButtons() } </View> ) } 

I moved the mapping to separate function outside of render method for more readable code. There are many other ways to loop through list of elements in react native, and which way you'll use depends on what do you need to do. Most of these ways are covered in this article about React JSX loops, and although it's using React examples, everything from it can be used in React Native. Please check it out if you're interested in this topic!

Also, not on the topic on the looping, but as you're already using the array syntax for defining the onPress function, there's no need to bind it again. This, again, applies only if the function is defined using this syntax within the component, as the arrow syntax auto binds the function.

2 Comments

If anybody has problems recreating this answer, recall that <Button /> is to be self closing (to my understanding) and to display text in them it has to be through the prop (property aka attribute) title="" More about Button here
Why renderButtons function has 2 return statements ?
3

If u want a direct/ quick away, without assing to variables:

{ urArray.map((prop, key) => { console.log(emp); return <Picker.Item label={emp.Name} value={emp.id} />; }) } 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.