By Mateo


2015-04-01 15:03:19 8 Comments

I'm building a simple app in React Native that fetches listings from a remote JSON source and displays them on screen.

So far, using the excellent example here, I've managed to get the results to display using the ListView components in rows (i.e. 1 result per row, see screenshot). I need the results to display in a grid, i.e. 3 to 6 items per row, depending on the screen size and orientation.

What is the best way to get these results into a grid? Can I use ListView for this, or is that only for one-per-row results? I've tried playing around with flexbox styles but, since React doesn't seem to accept % values and ListView doesn't accept styles, I haven't yet had any success.

This is how my listings are displaying at the moment - one per row.

8 comments

@Tim Perkins 2017-09-22 15:49:15

ListView is now deprecated and you should use FlatList instead. FlatList has a prop called numColumns which is exactly what we want to create a scrollable grid.

For example:

const data = [
  {id: 'a', value: 'A'},
  {id: 'b', value: 'B'},
  {id: 'c', value: 'C'},
  {id: 'd', value: 'D'},
  {id: 'e', value: 'E'},
  {id: 'f', value: 'F'},
];
const numColumns = 3;
const size = Dimensions.get('window').width/numColumns;
const styles = StyleSheet.create({
  itemContainer: {
    width: size,
    height: size,
  },
  item: {
    flex: 1,
    margin: 3,
    backgroundColor: 'lightblue',
  }
});

function Grid(props) {
  return (
    <FlatList
      data={data}
      renderItem={({item}) => (
        <View style={styles.itemContainer}>
          <Text style={styles.item}>{item.value}</Text>
        </View>
      )}
      keyExtractor={item => item.id}
      numColumns={numColumns} />
  );
}

enter image description here

This blog post does a good job explaining the new features of FlatList.

Note: For some reason you have to use keyExtractor on the FlatList instead of the typical key prop on each item. Otherwise you'll get a warning. Basic FlatList code throws Warning - React Native

@jdnichollsc 2018-02-23 21:48:30

Check the following example using FlatList component of React Native to support infinite scrolling with an excellent performance:

//Resize the grid
onLayout = (event) => { 
  const {width} = event.nativeEvent.layout;
  const itemWidth = 150
  const numColumns = Math.floor(width/itemWidth)
  this.setState({ numColumns: numColumns })
}

render() {
  return (
    <Content 
     contentContainerStyle={{flex:1, alignItems: 'center'}}
     onLayout={this.onLayout}>
       <FlatList
        data={this.state.products}
        keyExtractor={(item, index) => index}
        key={this.state.numColumns}
        numColumns={this.state.numColumns}
        renderItem={({item}) => 
          <ListThumb //Custom component, it's only an example.
           navigation={navigation}
           brand={item.brand}
           price={item.price}
           imageSource={item.image_link}/>
        }
     />
   </Content>
  )
}    

The example looks like

enter image description here

Best regards, Nicholls

@Moorthy 2017-07-06 12:32:02

use FlatList instead of Listview in react-native. it has more value added feature and better performance. checkout the example here

@nguyencse 2017-11-04 07:47:14

You can use FlatList and set numColumns to obtain the result which is the same with grid

@Pavle Lekic 2017-02-07 21:19:45

I had the same problem and I wrote a component that solves that problem, you can find it here: https://github.com/pavlelekic/react-native-gridview

Also, one other thing this component does is it makes sure that the items width is a whole number, so that the borders of items don't have antialiasing, they are clear and crisp.

@RedGiant 2017-03-05 12:16:40

It works in 0.42. Hope it gets more attention.

@leo7r 2017-04-28 20:46:00

This should be the right answer, thanks!

@pmont 2017-05-16 15:19:22

@Pavle Lekic, thanks for writing that library. I added an issue about renderHeader which doesn't size to the full width.

@Yi Feng Xie 2017-01-21 18:26:27

Follow Colin Ramsay's answer. And if you want half width for each item, try this way.

...
import { Dimensions } from 'react-native'; 
const { width, height } = Dimensions.get('window');
const gutter = 0; // You can add gutter if you want
...


const styles = StyleSheet.create({
  item: {
    width: (width - gutter * 3)/2,
    marginBottom: gutter,
    flexDirection: 'column',
    alignSelf: 'flex-start',
    backgroundColor: '#ff0000',
  },
  list: {
    flexDirection: 'row',
    justifyContent: 'space-between',
    flexWrap: 'wrap',
    paddingHorizontal: gutter,
  },
});

@Jagjot Singh 2017-02-06 12:37:53

I messed around a long time before stumbling to your answer down here. Thanks a ton for this!

@Yi Feng Xie 2017-02-06 15:49:47

you're welcome.

@kwishnu 2016-10-04 04:18:31

I'm adding this as an answer because overflow comments are hidden under Colin Ramsay's response: as of React Native 0.28, you also need alignItems: 'flex-start', in the listview styling or the flexWrap won't work. Thanks to Kerumen on codedump.io for this. So,

var styles = StyleSheet.create({
list: {
    flexDirection: 'row',
    flexWrap: 'wrap',
    alignItems: 'flex-start',
},

...with the rest as in Colin's response.

@ppsreejith 2016-10-29 10:39:10

This is such an important comment. Thanks :)

@kjonsson 2017-05-10 10:24:18

@kwishnu you are a god !

@Kerumen 2017-05-14 22:09:01

I didn't answered on codedump. It was on StackOverflow ;) stackoverflow.com/questions/39313268/…

@kwishnu 2017-05-15 22:24:52

@kerumen - sure enough! Somehow that question ended up at codedump.io/share/cSuUKROA1Mmx/1/… , which was where I found it...at any rate, Thank you! It has helped a lot of people, and I've up-voted your answers

@Colin Ramsay 2015-04-01 16:10:24

You need to use a combination of flexbox, and the knowledge that ListView wraps ScrollView and so takes on its properties. With that in mind you can use the ScrollView's contentContainerStyle prop to style the items.

var TestCmp = React.createClass({
    getInitialState: function() {
      var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
      var data = Array.apply(null, {length: 20}).map(Number.call, Number);
      return {
        dataSource: ds.cloneWithRows(data),
      };
    },

    render: function() {
      return (
        <ListView contentContainerStyle={styles.list}
          dataSource={this.state.dataSource}
          renderRow={(rowData) => <Text style={styles.item}>{rowData}</Text>}
        />
      );
    }
});

Just a ListView with some dummy data. Note the use of contentContainerStyle. Here's the style object:

var styles = StyleSheet.create({
    list: {
        flexDirection: 'row',
        flexWrap: 'wrap'
    },
    item: {
        backgroundColor: 'red',
        margin: 3,
        width: 100
    }
});

We tell the container we want items in a wrapping row, and the we set the width of each child object.

Screenshot

@Mateo 2015-04-01 19:47:16

Colin, thank you so much for this. I'll try it out.

@Mike Driver 2015-04-01 23:04:37

This is exactly what I was looking for for something I'm doing! Thanks!

@rxb 2015-04-02 16:08:45

THANK YOU! This is exactly what I was hoping for, but didn't think existed.

@miki725 2015-10-18 03:26:01

Would anybody here know how to make this work when using ListView with sections?

@Matt H 2016-01-15 15:10:41

How would you make the width of each child object equal to half of the parent container (for two equal sized children in each row)? I tried flex: .5 for the children with flex: 1 for the parent listview, bit it fails.

@Chalist 2016-01-26 17:22:37

For deferent height works? look like pinterest? stackoverflow.com/questions/35017978/…

@simonthumper 2016-05-13 13:29:48

@MattH did you ever get your half-width items to work?

@Jo Ko 2016-07-23 18:38:30

@ColinRamsay how would you make a grid with renderHeader as well? Because once renderHeader is applied, the contentContainerStyle does not work.

@iksnae 2017-01-13 20:35:49

thank you. Exactly what I needed.

@Jarsen 2017-04-25 17:00:22

Awesome!!! This is just what I wanted. Didn't want to use a grid view component from github. I can confirm this also works for FlatList

@IvRRimUm 2017-08-15 13:08:35

Just a P.S This actually works for View too. ListView is not mandatory for this to work.

Related Questions

Sponsored Content

5 Answered Questions

[SOLVED] React Native: Getting the position of an element

3 Answered Questions

[SOLVED] Setting up a table layout in React Native

  • 2017-06-04 18:12:33
  • jamesvphan
  • 15237 View
  • 10 Score
  • 3 Answer
  • Tags:   react-native

38 Answered Questions

[SOLVED] Lazy load of images in ListView

1 Answered Questions

Realm with React Native ListView will not render

2 Answered Questions

2 Answered Questions

1 Answered Questions

React Native Grid Layout with section headers

2 Answered Questions

Grid view on React Native Android

1 Answered Questions

[SOLVED] react-native listview some rows not displaying

5 Answered Questions

[SOLVED] React Native: ListView not displaying all rows

Sponsored Content