I'm trying to learn React-Native. I'm looking at an example, Responsive image grid by Joshua Sierles. (Thank you Joshua!) In this sample, Joshua uses React to carefully place image elements in a controlled manner across the mobile display. Note: he uses ONLY three images and repeats them several times within the document. Unfortunately, as written, the example generates a warning:
Warning: Each child in an array or iterator should have a unique "key" prop. Check the render method of
YourProjectNameHere
. See fb.me/react-warning-keys for more information. (Link extrapolated from the shortened form...)
I fully understand that each element within a row and each row generated by React must have a unique key property. What I'm not clear on is exactly how to do that. Here's my hack / work around. key={Math.random()}
This hack works fine, but it just seems so... wrong. The question here is, what is the right way to identify individual image ID's as well as identify individual row ID's?
'use strict';
var React = require('react-native');
var {
AppRegistry,
StyleSheet,
Text,
View,
Image,
Dimensions,
ScrollView
} = React;
var _ = require('lodash');
var {width, height} = Dimensions.get('window');
var IMAGE_URLS = _.flatten(_.times(9, () => {return ['http://rnplay.org/IMG_0599.jpg', 'http://rnplay.org/IMG_0602.jpg', 'http://rnplay.org/IMG_0620.jpg']})); // 9 x 3 = 27 images
var IMAGES_PER_ROW = 4;
var AwesomeProject1 = React.createClass({
getInitialState() {
return {
currentScreenWidth: width,
currentScreenHeight: height
}
},
handleRotation(event) {
var layout = event.nativeEvent.layout
this.setState({currentScreenWidth: layout.width, currentScreenHeight: layout.height })
},
calculatedSize() {
var size = this.state.currentScreenWidth / IMAGES_PER_ROW
return {width: size, height: size}
},
// note: I added key={Math.random()} in two places below.
// Its a BS fix, but it seems to work to avoid the warning message.
renderRow(images) {
return images.map((uri) => {
return (
<Image style={[styles.image, this.calculatedSize()]} key={Math.random()} source={{uri: uri}} /> //key={Math.random()}
)
})
},
renderImagesInGroupsOf(count) {
return _.chunk(IMAGE_URLS, IMAGES_PER_ROW).map((imagesForRow) => {
return (
<View style={styles.row} key={Math.random()}>
{this.renderRow(imagesForRow)}
</View>
)
})
},
render: function() {
return (
<ScrollView onLayout={this.handleRotation} contentContainerStyle={styles.scrollView}>
{this.renderImagesInGroupsOf(IMAGES_PER_ROW)}
</ScrollView>
);
}
});
var styles = StyleSheet.create({
row: {
flexDirection: 'row',
alignItems: 'center',
justifyContent: 'flex-start'
},
image: {
}
});
AppRegistry.registerComponent('AwesomeProject1', () => AwesomeProject1);
I've tried every combination of key=uri.id , imagesForRow.id, images.id, etc
that I can think of. None works as good as the Random Number function. Other ideas? What's the right way to do this?
Update per Chris Geirman's answer below: I wanted to show my final code.
renderRow(images) {
return images.map((uri, idx) => {
return (
<Image style={[styles.image, this.calculatedSize()]} key={uri.concat(idx)} source={{uri: uri}} /> //key={Math.random()}
)
})
},
renderImagesInGroupsOf(count) {
return _.chunk(IMAGE_URLS, IMAGES_PER_ROW).map((imagesForRow, idx2) => {
return (
<View style={styles.row} key={imagesForRow.concat(idx2)}>
{this.renderRow(imagesForRow)}
</View>
)
})
},