FlatList ref issue - react-native

I am not getting ref of the flatlist always getting
Warning: Function components cannot be given refs. Attempts to access
this ref will fail. Did you mean to use React.forwardRef()?
I am beginner in react-native
export default class ListData extends Component {
constructor(props) {
super(props);
this.state = {
flatListRef: null
};
}
render() {
return (
<View style={styles.container}>
<FlatList
data={countryList}
ref={ref => (this.state.flatListRef = ref)}
style={{ flex: 1 }}
showsVerticalScrollIndicator={false}
showsHorizontalScrollIndicator={false}
renderItem={({ item, index }) => (
<View style={[styles.ListViewContainer]}>
<Text style={styles.countryTxt}>
<Text> +{item.code}</Text>
<Text> {item.CountryName} </Text>
</Text>
</View>
)}
keyExtractor={(item, index) => index.toString()}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: 40,
backgroundColor: "white"
}
});

Using import { FlatList } from "react-native"
instead of
import { FlatList } from 'react-native-gesture-handler';
is working. But I am still want to why it's not working with 'react-native-gesture-handler'. while list is displaying correctly but ref is not getting.

try this:
in your constructor
this.flatListRef = React.createRef()
and then in your FlatList you do:
<FlatList ref={this.flatListRef} ...

Try passing ref={null} to your list item component.
renderItem={({ item, index }) => (
<View style={[styles.ListViewContainer]} ref={null}>

Related

React Native Keyboard Avoiding View

I'm trying to implement a flatlist of comments alongside a textinput at the bottom. However, when I try to place the textinput in a keyboard avoiding view so that it gets pushed to the top to see the input being typed in, it doesn't go to the top and stays at the bottom. Here is my code:
render() {
return (
<KeyboardAvoidingView enabled behavior='padding' style={styles.container}>
<View style={styles.commentStyles}>
<FlatList
keyExtractor={(item) => JSON.stringify(item.date)}
data={this.props.post.comments}
renderItem={({item}) => (
<View style={[styles.row, styles.commentContainer]}>
<Image style={styles.roundImage} source={{uri: item.commenterPhoto}}/>
<View style={[styles.left]}>
<Text>{item.commenterName}</Text>
<Text style={styles.commentText}>{item.comment}</Text>
</View>
</View>
)}
/>
<TextInput
style={styles.input}
onChangeText={(comment) => this.setState({comment})}
value={this.state.comment}
returnKeyType='send'
placeholder='Add Comment'
onSubmitEditing={this.postComment}
/>
</View>
</KeyboardAvoidingView>
);
}
My container just has a flex: 1 styling applied to it. I tried reading through the documentation for KeyboardAvoidingView but found it to be very confusing. If you guys can help me in any way, would greatly appreciate it!
Give this a try.
import React, {Component} from 'react';
import {
StyleSheet,
Text,
View,
KeyboardAvoidingView,
Platform,
Dimensions,
TextInput
} from 'react-native';
const {height: fullHeight} = Dimensions.get('window');
class Comment extends Component {
constructor(props) {
super(props);
this.state = {
pageOffset: 0,
};
}
onLayout = ({
nativeEvent: {
layout: {height},
},
}) => {
const pageOffset =
fullHeight - height;
this.setState({pageOffset});
};
render() {
return (
<View style={styles.viewContainer} onLayout={this.onLayout}>
<KeyboardAvoidingView
style={styles.container}
keyboardVerticalOffset={this.state.pageOffset}
behavior={Platform.OS === 'ios' ? 'padding' : null}>
<FlatList
keyExtractor={(item) => JSON.stringify(item.date)}
data={this.props.post.comments}
renderItem={({item}) => (
<View style={[styles.row, styles.commentContainer]}>
<Image style={styles.roundImage} source={{uri: item.commenterPhoto}}/>
<View style={[styles.left]}>
<Text>{item.commenterName}</Text>
<Text style={styles.commentText}>{item.comment}</Text>
</View>
</View>
)}
/>
<TextInput
style={styles.input}
onChangeText={(comment) => this.setState({comment})}
value={this.state.comment}
returnKeyType='send'
placeholder='Add Comment'
onSubmitEditing={this.postComment}
/>
</KeyboardAvoidingView>
</View>
);
}
}
export default Comment;
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'space-between',
},
viewContainer: {
flex: 1,
},
});

react-native FlatList scroll to bottom for chat app

I've made a chat app, and for rendering messages flatlist is used. But the problem is tried to scroll to the end of the screen every time the page is loaded, but it fails to do so. I've tried inverted props, but nothing happened, only the list got inverted.
Even played with ref to make it auto-scroll to the bottom, but nothing happened.
<FlatList
ref="flatList"
onContentSizeChange={() =>
this.refs.flatList.scrollToEnd()}
contentContainerStyle={{
marginBottom:
verticalScale(200)
}}
style={styles.list}
data={this.state.messages}
/>
How to make it scroll to the bottom the screen or scroll to the last index of the message when rendered?
(UPDATE)
IT WAS AN ISSUE WITH THE <Content/> component i used which belongs to native-base . Upon removing and replacing it with a <View/> it works perfectly fine.
Also, for chat based app the inverted prop in Flatlist is the way to implement in right way.
I've added the way i managed to scroll in the answer below. If you simply want your app to display the last item in the list and stays there, you can use inverted
You should use ref like this:
export default class MyAwesomeComponent extends React.Component {
FlatListRef = null; // add a member to hold the flatlist ref
render() {
return (
<FlatList
ref={ref => (this.FlatListRef = ref)} // assign the flatlist's ref to your component's FlatListRef...
onContentSizeChange={() => this.FlatListRef.scrollToEnd()} // scroll it
contentContainerStyle={{marginBottom: verticalScale(200)}}
style={styles.list}
data={this.state.messages}
/>
);
}
}
prueba esto
return (
<View style={{flex: 1}}>
<KeyboardAvoidingView
behavior="padding"
style={styles.keyboard}
keyboardVerticalOffset={height - 1000}>
<FlatList
ref={ref => (this.FlatListRef = ref)}
onContentSizeChange={() => this.FlatListRef.scrollToEnd()} // scroll it
// contentContainerStyle={{marginBottom: verticalScale(200)}}
// keyboardShouldPersistTaps='always'
style={styles.list}
extraData={this.state}
data={this.state.messages}
keyExtractor={item => {
return item.id;
}}
renderItem={e => this._renderItem(e)}
/>
<View style={styles.input}>
<TextInput
// style={{flex: 1}}
value={msg}
placeholderTextColor="#000"
onChangeText={msg => this.setState({msg: msg})}
blurOnSubmit={false}
onSubmitEditing={() => this.send()}
placeholder="Escribe el mensaje"
returnKeyType="send"
/>
</View>
</KeyboardAvoidingView>
</View>
);
You can use Javascript method to reverse to show your messages from end
messages.reverse()
scrollToListPosition = (index) => {
const itemOffset = this.getItemOffset(index)
this.flatListRef.scrollToOffset({ animated: false, offset: itemOffset })
}
getItemOffset = (index) => {
let heightsum = 0
for (i = 0; i < index; i++) {
heightsum = heightsum + this.itemHeight[i]
}
return heightsum
}
render(){
return (
<FlatList
ref={(ref) => { this.flatListRef = ref; }}
data={postList}
keyExtractor={(item, index) => item._id}
horizontal={false}
extraData={this.state}
keyboardShouldPersistTaps='always'
refreshing={this.props.isRefreshing}
onRefresh={this.handleRefresh}
onEndReached={this.handleLoadMore}
getItemLayout={(data, index) => (
{ length: this.getLength(index), offset: this.getLength(index) * index, index }
)}
renderItem={({ item, index }) => {
return (
<View onLayout={(event) => {
var { height } = event.nativeEvent.layout;
this.itemHeight[index] = height
}}
>
<ListCommon
key={index}
item={item}
index={index}
parentFlatList={this}
data={item}
instance={this.props.commanAction}
tag={this.state.tag}
changeRoute={this.props.changeRoute}
/>
</View>
);
}}
/>
)
}
getLength = (index) => {
if (this.itemHeight[index] === undefined) {
return 0;
}
return this.itemHeight[index]
}
Here is how i solved it:
export default class Test extends Component {
constructor(props) {
super(props);
}
componentDidMount() {
setTimeout(() => {
this.FlatListRef.scrollToEnd();
}, 1500);
}
render() {
return (
<View style={{ flex: 1 }}>
<FlatList
data={[1, 2, 3, 4, 5, 6, 7, 8]}
ref={(ref) => (this.FlatListRef = ref)}
renderItem={({ item }) => {
return (
<View
style={{
height: 140,
width: 400,
backgroundColor: "yellow",
alignItems: "center",
justifyContent: "center",
}}
>
<Text>{item}</Text>
</View>
);
}}
/>
</View>
);
}
}

React-native: how to highlight a flatlist item when it is touched

I have a flatlist and I want a background color to appear on an item in the list when it is touched. See image below; this is what should happen if I touch "game_name3":
But nothing happens; it stays looking like the screen on the left.
Here is my code:
constructor (props) {
super(props);
this.state = {
...
game_names: [
{game_name:"game_name1", players:4},
{game_name:"game_name2", players:4},
{game_name:"game_name3", players:4},
{game_name:"game_name4", players:4},
{game_name:"game_name5", players:4},
{game_name:"game_name6", players:4},
],
game_selected: '',
...
}
}
...
selectPublicGame = (game) => {
this.setState({game_selected: game});
}
renderItem = ({item}) => {
const unselected_game =
<View style={{flexDirection: 'row', flex: .5, justifyContent: 'space-between'}}>
<Text style={[styles.listText, styles.textPaddingHorizontal]}>
{item.game_name}
</Text>
<Text style={[styles.listText, styles.textPaddingHorizontal]}>
({item.players}/6)
</Text>
</View>;
const selected_game =
<View style={{flexDirection: 'row', flex: .5, justifyContent: 'space-between', backgroundColor: colors.JBTealTrans}}>
<Text style={[styles.listText, styles.textPaddingHorizontal]}>
{item.game_name}
</Text>
<Text style={[styles.listText, styles.textPaddingHorizontal]}>
({item.players}/6)
</Text>
</View>;
let selection;
if (item.game_name == this.state.game_selected) {
selection = selected_game
} else {
selection = unselected_game
}
return (
<TouchableWithoutFeedback
onPress={() => this.selectPublicGame(item.game_name)}
>
{selection}
</TouchableWithoutFeedback>
)
}
...
render() {
...
return(
...
<FlatList
data={this.state.game_names}
renderItem={this.renderItem}
keyExtractor={(item, index) => index.toString()}
/>
...
)
}
...
Each item in the flatlist is wrapped in TouchableWithoutFeedback, onPress sets the game_selected state to the game name that was selected. The items are conditionally rendered. If the game name is the same as the game_selected state, it should render the "selected_game" constant, which has the backgroundColor style, but is not doing anything for some reason.
FlatList is a pure component and only re-renders if strict equality checking on its data or extraData props returns false. Since your component rendering depends on state.game_selected that will need to be included in extraData:
<FlatList
data={this.state.game_names}
renderItem={this.renderItem}
keyExtractor={(item, index) => index.toString()}
extraData={this.state.game_selected}
/>

How to make FlatList fill the height?

import React from 'react';
import {SafeAreaView, KeyboardAvoidingView, FlatList, View, Text, TextInput, Button, StyleSheet } from 'react-native';
export default class Guest extends React.Component {
state={
command: '',
}
constructor(props) {
super(props)
this.onChangeText = this.onChangeText.bind(this)
this.onKeyPress = this.onKeyPress.bind(this)
this.onSubmit = this.onSubmit.bind(this)
}
onChangeText(text){
const command = text.replace('\n', '');
this.setState({
command: command
})
}
onKeyPress(e){
}
onSubmit(){
}
render() {
return(
<SafeAreaView style={styles.safeAreaView}>
<KeyboardAvoidingView style={styles.keyboardAvoidingView} keyboardVerticalOffset={88} behavior="padding" enabled>
<FlatList
inverted={true}
keyboardShouldPersistTaps='always'
keyboardDismissMode='interactive'
ref='list'
style={styles.flatList}
data={[1, 2, 3]}
renderItem={(props) => {
return(<View><Text>{props.item}</Text></View>)
}}
/>
<TextInput
command={this.state.command}
onChangeText={this.onChangeText}
onKeyPress={this.onKeyPress}
onSubmit={this.onSubmit}
style={styles.textInput}
/>
</KeyboardAvoidingView>
</SafeAreaView>
)
}
}
const styles = StyleSheet.create({
safeAreaView:{
backgroundColor:"#ffffff",
},
keyboardAvoidingView:{
},
flatList:{
backgroundColor: 'red',
},
textInput:{
backgroundColor: 'yellow'
}
})
I'd like the red flatList to fill the screen (but keep height of yellow textbox).
I've tried flex:1 on flatList, but it simply makes it disappear.
FlatList inherits ScrollView's props, so solution for ScrollView will work:
<FlatList
contentContainerStyle={{ flexGrow: 1 }}
{...otherProps}
/>
Here is the original Github issue for above solution.
EDIT: The parental Views of FlatList should have flex: 1 in their style.
safeAreaView:{
backgroundColor:"#ffffff",
flex: 1
},
keyboardAvoidingView:{
flex: 1
},
use the property style wit flex:
render() {
return (
<View style={{ flex: 1 }}>
<FlatList
keyExtractor = { this.keyExtractor }
data = { this.getPOs() }
ListEmptyComponent = { this.renderEmpty }
ItemSeparatorComponent = { Separator }
renderItem = { this.renderItem }
/>
</View>
)
}
No need to add a parental view to the list, simply:
render() {
return <FlatList style={{width: '100%', height: '100%'}}
{...others}
/>;
}
you can also add height in flatList style or put flatlist inside a view and then add flex for view
In my case the problem was with virtual keyboard. when I open another page. then the keyboard suddenly dismiss. and it cause part of the page to be like someone cut it or clean it. so the solution is to before push the page that contain flatlist first dismiss the keyboard and then navigate to new page
I try every response on this issue but none of them work.
What I do was add a Parent to the FlatList and then give it a style :
<View style={{ height: SCREEN_HEIGHT}}>
SCREEN_HEIGHT is from Dimensions.get('window')
you have to import from "react-native" like this:
import { Dimensions } from "react-native"
Full example:
<View style={{ height: SCREEN_HEIGHT}}>
<FlatList
contentContainerStyle={{ flexGrow: 1 }}
keyExtractor={item => item.name}
numColumns={1}
data={this.state.dataList}
renderItem={({ item, index }) =>
this._renderItemListValues(item, index)
}
/>
</View>

How to populate a Flatlist from TextInput

I am trying to populate a FlatList row with the value coming from a TextInput.
Below you can find my current code.
import React, { Component } from 'react'
import { View, Text, TouchableOpacity, TextInput, StyleSheet,
StatusBar, FlatList } from 'react-native'
globalText = require('../styles/Texts.js');
globalColors = require('../styles/Colors.js');
class SearchInput extends Component {
constructor(props) {
super(props);
this.state = {
data: [],
ingredients: ''
}
}
_handleIngredients = (text) => {
this.setState({ ingredients: text })
}
render(){
return (
<View style={styles.container}>
<StatusBar barStyle="dark-content"/>
<View>
<TextInput style={[globalText.btnFlatPrimary, styles.inputText]}
underlineColorAndroid='transparent'
placeholder='Add ingredients'
placeholderTextColor={globalColors.lightGrey}
autoCapitalize='sentences'
autoCorrect={false}
autoFocus={true}
onChangeText={this._handleIngredients}
keyboardShouldPersistTaps='handled'
/>
</View>
<FlatList
data={this.state.data}
renderItem={({text}) => (
<View style={styles.cell}>
<Text style={globalText.btnFlatPrimary}>{this.state.ingredients}</Text>
</View>
)}
/>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
paddingTop: 20,
backgroundColor: globalColors.white,
},
inputText: {
paddingLeft: 16,
paddingRight: 16,
height: 60
},
cell: {
height: 60,
paddingLeft: 16,
justifyContent: 'center',
}
});
export default SearchInput;
I am probably missing something but if I pre populate the data and the ingredients states, then FlatList display correctly with the entered values. What I'd like it to populate the Flalist with the TextInput
data: [{key:'a'}],
ingredients: 'tomato'
Flatlist will only re-render if the data property changes. If you want it to re-render based on other values, you would need to pass an extraData prop.
<FlatList
data={this.state.data}
extraData={this.state.ingredients} //here
renderItem={({text}) => (
<View style={styles.cell}>
<Text style={globalText.btnFlatPrimary}>{this.state.ingredients}</Text>
</View>
)}
/>
Read more here: https://facebook.github.io/react-native/docs/flatlist.html#extradata
change: onChangeText={this._handleIngredients}
to: onChangeText={(text) => this._handleIngredients(text)}
This is for preserving the scope of this.