Dynamically changing number of columns in React Native Flat List - reactjs

I have a FlatList where I want to change the number of columns based on orientation. However, I get the red screen when I do this. As per the red screen error message, I'm not quite sure how I should be changing the key prop. Any help is appreciated.
// dynamically changing number of columns
const numCols = orientation === constants.PORTRAIT ? 3 : 8
<FlatList
keyExtractor={(_, i) => i}
numColumns={numCols} // assigning the number of columns
horizontal={false}
renderItem={({ item }) => <ListItem imageUrl={item.url} />}
/>}

From the documentation, looks like you should do something like this
key={(this.state.horizontal ? 'h' : 'v')}

I did it using key
numColumns = {this.state.columnCount}
key={this.state.columnCount}

Pass a changing value to the FlatList itself. It has nothing to do with the keyExtractor or the key attrbibute in renderItem methods:
<FlatList key={changingValue} .. />
should solve it.

In Hooks
const [numCols, setColumnNo] = useState(0);
<FlatList
key={numCols}
numColumns={numCols}
...
/>

<FlatList
data={props.localFolders}
style={{ width: "100%" }}
numColumns={4}
key={4}
renderItem={({ item }) => <LocalFolder {...item} />}
keyExtractor={(item) => item.id.toString()}
/>
works for me

I think the message is very clear. You need to define different keys for portrait/landscape if you want to change the number of columns to force a fresh re-render. Try concatenating the numCols value to the index in your keyExtractor.

If you need to make your app responsive when is landscape mode, try this:
const {height, width} = useWindowDimensions();
const isLandscape = width > height;
<FlatList
numColumns={Number(isLandscape) + 1}
keyExtractor={item => item.id}
key={Number(isLandscape)}
...
This will convert boolean into number.
Note useWindowDimensions is imported from react-native.

Related

How to Limit render element Flat List and add more content in React Native

I want like that flatlist render only 5 checkbox items and then when I click to +5 more button it will show 5 more checkbox list.In this all checkbox list appearing but i want only five
Please help me how to achieve that
Thanks in advance
const renderResourceList = renderData => {
return (
<FlatList
data={renderData}
initialNumToRender={5}
maxToRenderPerBatch={5}
pagingEnabled={true}
nestedScrollEnabled={true}
renderItem={({item}) => (
<View style={styles.card}>
<TouchableOpacity
onPress={() => {
if(resourceTypeArray.includes(item)){
setResourceTypeArray(currentList => {
return currentList.filter(items => items !== item);
});
}
else{
setResourceTypeArray(currentList => [
...currentList,
item
]);
}
onSetResourceType(item);
}}
style={styles.modalBtn}>
<Icon
name={
resourceTypeArray.includes(item) ? 'checkbox-marked' : 'checkbox-blank-outline'
}
size={18}
color="#353C3C"
style={{bottom: -1}}
/>
<View style={styles.textWrapper}>
<Text style={styles.modalText}>{item.charAt(0)}
{item.toLowerCase().slice(1).replace(/_/g, ' ')}</Text>
</View>
</TouchableOpacity>
</View>
)}
/>
);
};
I tried but this not working
I used a package called flatlist-react to handle this for me. A decent tutorial for this can be found here.
With this package, you can directly specify and limit the items rendered with the limit prop. Here is an example:
<FlatList
limit="2,-2"
list={people}
renderItem={Person}
/>
If you keep track of the limit prop variables using state, you can dynamically change these values when you click 5+ more in order to render whatever part of your data you would like.

FlatList rendering is heavy for big data set

In my application I have a FlatList with dataset of 100 items in it. Each item has a complex UI and I noticed that it's taking a heavy toll on performance. The page that has the list takes up to 5 seconds to load.
I noticed that the moment the component is rendered for the first time, the renderItem function of the FlatList is also called for each and every item in my data set, I also noticed that it also happens if there any other setState change for other stuff on that page. Is there a way to prevent this re-rendering of the flat list or at least to re-render only the visible items - just like with Recycle with in native Android?
How can I only render the visible items when the component first appears?
I tried to use initialNumToRender and maxToRenderPerBatch but neither have worked.
Here is an example of the code:
const Item = ({ title }) => (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
</View>
);
const App = () => {
const [text, setText] = React.useState('')
const renderItem = ({ item }) => {
console.log("Render Item")
return (<Item title={item.title} />)
};
return (
<SafeAreaView style={styles.container}>
<TextInput
value={text}
onChangeText={(val) => setText(val)}
/>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={item => item.id}
initialNumToRender={6}
maxToRenderPerBatch={6}
/>
</SafeAreaView>
);
}
If I try to type something in TextInput the whole list re-renders but nothing in the list has changed.. how can I prevent this?

FlatList showing 10 items until render() is called

I have a FlatList component that renders 20 items. When I load up the page in React Native, my FlatList shows 10 items. Once a render has occurred, the next 10 are loaded.
<FlatList
data={data}
keyExtractor={(item, i) => String(i)}
showsVerticalScrollIndicator={false}
contentContainerStyle={styles.boardList}
renderItem={({ item, index }) => (
<Item {...item}/>
)}
/>
data is simply an Array of JSON objects.
You should set following properties
initialNumToRender={20}
maxToRenderPerBatch={20}
As the default is 10
It may be better to use ScrollView and .map(() = > {}) ?
Add style={{ flex: 1 }} in FlatList

React-native FlatList items not get to right height

I have items in diffrent heights (250 or 150) inside a FlatList,
When iterate each item and append the state of the dataSrouce for the FlatList everything renders alright, but if I want to avoid the "appending" affect and set the dataSrouce to all of the items at once, it seem FlatList have a wierd bug where items are not getting their right height (There is a blank space on the botton where the item had suppose to fill it).
Tried put "flexGrow:1" on the FlatList, tried the "initialNumToRender" property,
Tried to fix height of the each Item in the view.
Container of the FlatList is "flex:1".
My FlatList:
render() {
const _this = this;
const { loading } = this.state;
return (
<Components.ViewContainer>
{this.printTopHeader()}
{loading ? (
<ActivityIndicator size={25} />
) : (
<FlatList
style={{ flex: 1 }}
removeClippedSubviews={true} //tried with and without
data={this.state.posts}
extraData={this.state.posts} //tried with and without
renderItem={({ item }) => (
<HomeCard
post={item}
/>
)}
keyExtractor={(item, index) => item.key}
/>
)}
</Components.ViewContainer>
);
}
Components.ViewContainer:
const ViewContainer = styled.View`
flex:1;
`;
HomeCard:
render() {
const { theme, showActions } = this.props;
const {
imageUrl,
user,
title,
selectedPlace,
textColor,
backgroundColor
} = this.props.post;
return (
<Components.ContainerView>
...
</Components.ContainerView>
);
}
export default withTheme(HomeCard); // styled-components implementation
The issue were caused by a matter of wrong styling applied to the child elements,
By better understand how FlexBox works I managed to figure that I was missing a flex: 1 attribute on the list elements, and therefore the items styling didn't calculated correctly.

Big Space between items in FlatList

I'm implementing Comment Page like Facebook. Somehow I'm getting a plenty of white space. Check this out!
When I scroll it to the bottom... the rest of comments are there.. so weird
Here is my render function and FlatList
render() {
return (
<RkAvoidKeyboard style={styles.bigContainer} onResponderRelease={(event) => {
Keyboard.dismiss();
}}>
<FlatList
ref='list'
style={styles.root}
data={this.props.comments}
ItemSeparatorComponent={this._renderSeparator}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}/>
{this._renderKeyboard()}
</RkAvoidKeyboard>
)
}
_keyExtractor(item, index) {
return item.id;
}
_renderSeparator() {
return (
<View style={styles.separator}/>
)
}
I set the background color of the FlatList and it colors all screen (except the keyboard and navigation). I didn't notice this until I implement my Keyboard input. So nothing wrong with Keyboard.
This is so werid..!!
To me the space looks exactly the size of keyboard, instead of using the RkAvoidKeyboard spacer, try using react-native-keyboard-spacer
Its easy to set up and you will just have to set it under your comment textInput component or at the bottom of the container whichever suits you.
Here is a sample that I can provide and that may help you
<View>
<FlatList
data = {dataSource}
renderItem = {({item}) => this._renderFlatListItem(item)}
keyExtractor = {(item) => item.id}
/>
<View style={style.textInputContainer}>
<TextInput
placeholder={"Text goes here"}
ref={input => { this.textInput = input }}
onChangeText={(text) => this.setState({currentMessage:text})}
value={this.state.message}
multiline={true}
underlineColorAndroid = {'transparent'}
/>
<TouchableHighlight
underlayColor={'transparent'}
style={style.sendButtonContainer}
onPress = {() => {this._sendMessage();}}>
<Image source={require('../../Assets/Images/shape.png')}
style={style.sendButton} resizeMode="contain"/>
</TouchableHighlight>
</View>
<KeyboardSpacer/>
All the best!
I was getting null for my Avatar Image and that showed huge blank list.
I figured this out while printing all comments on console.
Thank you guys!

Resources