Author: Ho Yin Cheng
Created: February 15, 2018
First in a new series of posts that I’ll be calling Code Dive. I like testing the depth of my React Native knowledge by answering questions on StackOverflow. Occasionally, I’ll run into a question that asks about the same exact issue I ran into and was forced to look into the source code to understand. So I take the time to redo the code dive and write out a summary/explanation of what I discovered. For any that I feel were particularly useful, I’ll be reposting them here.
For my very first report, I’ll be explaining why headers and footers are not included in the columns for React Native’s
FlatList component when using the
numColumns prop. Originally asked here.
I would love to be proven wrong here, but as far as I can tell, this cannot be done using
numColumns. There is a workaround which I’ll list at the end, but first the reasoning:
I ran into this same issue but with the footer and did a code dive into the React Native source to see what was happening. First thing I did was use the inspector and I noticed that the header and footer of a
FlatList are wrapped in a
View while each row of columns is wrapped in
CellRenderer > View. This is the first clue that
FlatList does not account for headers and footers in
numColumns. This is problematic because
FlatList does not support masonry type layouts. This hints at the fact that there are many assumptions being made about how they are handling rendering the rows - that is, items are separated into rows to be rendered.
With these clues, I went into the source and found that
FlatList passes its own custom
renderItem down to
ListFooterComponent are passed down as is. They are never used in
FlatList. Not a good sign as you’ll see that the aforementioned
_renderItem is what handles grouping the items together into columns to render using
flexDirection: 'row' and whatever is passed down with
But perhaps VirtualizedList is smart enough to combine the header and footer into
data that gets passed into
Sadly, this is not the case. If you follow the code in
VirtualizedList, you’ll eventually see all the logic get played out in
cellsarray is created
datapushed into it via its
FlatLists _renderItem is used explaining why you get
numColumnsnumber of items wrapped in a
cellsarray of React components is then eventually cloned which helps with things such as keeping scroll position.
Do to this implementation, you will always get a fixed
CellRenderer component which prevents headers and footers from being included as part of
Workaround (not recommended)
If you’ve used React Native prior to
FlatList being released, you’ll know that one old workaround was to be very careful with your dimensions and use
flexWrap: 'wrap'. It’s actually documented within the source code as it will spit out a warning if you use this method of handling columns. Do note that it is NOT recommended to do this (I believe performance and perhaps scroll position may be some of the reasons against using this method).
If you are willing to do this though, add these styles to your
flexDirection: 'row', flexWrap: 'wrap', // You'll probably also want this for handling empty cells at the end: justifyContent: 'flex-start',
and remove the
numColumns prop. Then make sure to manually size your component dimensions to get the correct looking column style layout you desire. This should allow your header and footer to render as part of the columns.
Copyright © 2011-2020 Ho Yin Cheng