React-Warning-Keys in FlatList - react-native

I have some FlatList in my render but I'm getting Unique Key warning, I tried to use keyExtractor as well but it didn't work for me.
here is my code :
<FlatList
data={this.state.itemWaiting}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item, index }) => (
<MatchTurnList
username={item.home_user.username}
opponent={item.away_user.username}
matches={item.round_results}
turnID={item.turn_id}
matchID={item.match_id}
userID={item.home_uid}
Rounds={item.round}
gameStatus={item.status}
onPress={() => console.log('hi')}
/>
)}
/>
and this is my warning :
Warning: Each child in a list should have a unique "key" prop.
Check the render method of MatchTurnList. See ..... for more information.
and here is my matchTurnList component :
return (
<TouchableOpacity onPress={onPress} activeOpacity={0.9} style={styles.gameStatus}>
<View style={{ flex: 2, justifyContent: 'center', alignItems: 'flex-start' }}>
<Text style={[globalStyles.mediumFont, globalStyles.lightColor, globalStyles.acmeFont, { margin: normalize(1) }]}>{username}</Text>
<View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
{a}
</View>
</View>
<View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
<Text style={[globalStyles.fontRifficFree, globalStyles.largFont, { color: '#ffbd00' }]}>VS</Text>
</View>
<View style={{ flex: 2, justifyContent: 'center', alignItems: 'flex-end' }}>
<Text style={[globalStyles.mediumFont, globalStyles.lightColor, globalStyles.acmeFont, { margin: normalize(1) }]}>{opponent}</Text>
<View style={{flexDirection: 'row', flexWrap: 'wrap'}}>
{b}
</View>
</View>
</TouchableOpacity>
);
could you please help me to find where my mistake is?
Thanks.

You should use flatlist like this
render(){
return(
<FlatList
data={this.props.data} //<- your data array
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
)
}
then use keyExtractor function in your component like this
_keyExtractor = (item, index) => String(item.yourID) //<- this id from your data.
and final _renderItem function like this
_renderItem = (item) => {
<View>
...your code to render UI...
</View>
}

Try my code.
you need to add key props in render method
<FlatList
data={this.state.itemWaiting}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item, index }) => (
<MatchTurnList
key={index}
username={item.home_user.username}
opponent={item.away_user.username}
matches={item.round_results}
turnID={item.turn_id}
matchID={item.match_id}
userID={item.home_uid}
Rounds={item.round}
gameStatus={item.status}
onPress={() => console.log('hi')}
/>
)}
/>
it will remove your warnings for uniques key.

Related

1st index hidden Item not hidding when swiping the another element - swiperFlatList React native

as you can see in the image, I have implemented adding Text inputs dynamically with the button press, everything is working perfectly only the 1st text input hidden item (Remove Button) not hiding when swiping the other text inputs.
const initialState = {
col1: '',
key: 0,
};
const [inputField, setInputField] = useState<Values[]>([initialState]);
<SwipeListView
data={inputField}
renderItem={data => renderItem(data)}
renderHiddenItem={data => renderHiddenItem(data)}
leftOpenValue={55}
rightOpenValue={-100}
disableRightSwipe={true}
ListHeaderComponent={
<View style={[styles.headingContainer]}>
<Text style={[styles.headingText]}>{Props.inputHeading}</Text>
</View>
}
ListFooterComponent={
<View style={styles.buttonContainer}>
<TouchableOpacity
style={styles.addBtn}
activeOpacity={0.7}
onPress={onPressAddBtn}>
<Text style={styles.BtnText}>Add</Text>
</TouchableOpacity>
<TouchableOpacity style={styles.submitBtn} activeOpacity={0.7}>
<Text style={styles.BtnText}>Submit</Text>
</TouchableOpacity>
</View>
}
style={{height: Dimensions.get('screen').height / 1.3}}
/>
const renderItem = (data: any) => {
return (
<TouchableHighlight key={data.item.key}>
<TextInput
placeholder="Hello"
onChangeText={e => handleChange(data.item.key, 'col1', e)}
value={data.item.col1}
style={[styles.textInput, Props.textInputStyle]}
// {...Props.textInputProps}
/>
</TouchableHighlight>
);
};
const renderHiddenItem = (rowData: any) => {
return (
<View
style={{
justifyContent: 'flex-end',
flexDirection: 'row',
alignItems: 'center',
}}>
<TouchableOpacity
activeOpacity={0.7}
style={{
backgroundColor: 'red',
justifyContent: 'center',
flexDirection: 'row',
width: 90,
height: 45,
alignItems: 'center',
borderRadius: 5,
}}>
<Text style={{color: 'white'}}>Remove</Text>
</TouchableOpacity>
</View>
);
};
but other all element's swipe is working as expected only the first element is not working as expected
found solution by adding keyExtractor={item => item.key.toString()} to swiper flatlist.

How to put FlatList inside of the ScrollView in React-native?

I know these kind of questions have in the stackoverflow before. But I cannot the find the correct solution for this problem.
Have any solution for put <FlatList/> inside of the <ScrollView></ScrollView> in react-native?
here is my code...
<ScrollView
onScroll={(e) => {
onScroll(e);
}}
stickyHeaderIndices={[1]}
contentContainerStyle={{ flexGrow: 1, justifyContent: 'center' }}
style={{ width: '100%' }}
>
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}>
{isLoading ? (
<DotIndicator color="#4cd137" style={{ marginBottom: 200 }} />
) : (
<FlatList
data={data}
keyExtractor={(item, index) => String(index)}
renderItem={({ item }) => (
<View
style={{
flex: 0,
padding: 5,
}}>
<Card style={styles.card}>
<CardItem header style={styles.cardText}>
<Title style={styles.textSign}>{item.question}</Title>
</CardItem>
<CardItem style={styles.cardText1}>
<Body>
<Paragraph>{item.answer}</Paragraph>
</Body>
</CardItem>
</Card>
</View>
)}
/>
)}
</View>
</ScrollView>
Error gives as follow:
ERROR VirtualizedLists should never be nested inside plain
ScrollViews with the same orientation because it can break windowing
and other functionality - use another VirtualizedList-backed container
instead.
I found the solution for that. I put my <ScrollView></ScrollView> component codes inside of <FlatList> ListHeaderComponent props.
Here is how it looks. I'm pretty sure this should works for every-one
I found that solution from here. you can refer it and can understandable it very easily.
How to Fix 'VirtualizedLists should never be nested inside plain ScrollViews' Warning
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}>
{isLoading ? (
<DotIndicator color="#4cd137" style={{ marginBottom: 200 }} />
) : (
<FlatList
data={data}
ListHeaderComponent={ //here I write ListHeaderComponent and put all code lines of `<ScrollView></ScrollView>` in here
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}>
<Image
source={require('../assets/Interview.png')}
width="100%"
height="0"
style={styles.logo2}
/>
</View>
}
keyExtractor={(item, index) => String(index)}
renderItem={({ item }) => (
<View
style={{
flex: 0,
padding: 5,
}}>
<Card style={styles.card}>
<CardItem header style={styles.cardText}>
<Title style={styles.textSign}>{item.question}</Title>
</CardItem>
<CardItem style={styles.cardText1}>
<Body>
<Paragraph>{item.answer}</Paragraph>
</Body>
</CardItem>
</Card>
</View>
)}
/>
)}
</View>
You can do this by,
<ScrollView>
<ScrollView horizontal={true}> // add this
<FlatList />
<ScrollView/>
<ScrollView>
this happens because inside the FlatList there is a ScrollView too, what you can do is wrap your FlatList in a View to separate the Scroll's
InnerWrapper is only another View
you can wrapper you FlatList like this:
<ScrollView
onScroll={(e) => {
onScroll(e);
}}
stickyHeaderIndices={[1]}
contentContainerStyle={{ flexGrow: 1, justifyContent: 'center' }}
style={{ width: '100%' }}
>
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}>
{isLoading ? (
<DotIndicator color="#4cd137" style={{ marginBottom: 200 }} />
) : (
<InnerWrapper>
<FlatList
data={data}
keyExtractor={(item, index) => String(index)}
renderItem={({ item }) => (
<View
style={{
flex: 0,
padding: 5,
}}>
<Card style={styles.card}>
<CardItem header style={styles.cardText}>
<Title style={styles.textSign}>{item.question}</Title>
</CardItem>
<CardItem style={styles.cardText1}>
<Body>
<Paragraph>{item.answer}</Paragraph>
</Body>
</CardItem>
</Card>
</View>
)}
/>
</InnewWrapper>
)}
</View>
</ScrollView>
As you don't have any other element don't use ScrollView. Use this code as flatlist will itself scroll at its elements.
<View
style={{
flex: 1,
alignItems: 'center',
justifyContent: 'center',
}}>
{isLoading ? (
<DotIndicator color="#4cd137" style={{ marginBottom: 200 }} />
) : (
<FlatList
style={{flex:1}}
data={data}
keyExtractor={(item, index) => String(index)}
renderItem={({ item }) => (
<View
style={{
flex: 0,
padding: 5,
}}>
<Card style={styles.card}>
<CardItem header style={styles.cardText}>
<Title style={styles.textSign}>{item.question}</Title>
</CardItem>
<CardItem style={styles.cardText1}>
<Body>
<Paragraph>{item.answer}</Paragraph>
</Body>
</CardItem>
</Card>
</View>
)}
/>
)}
</View>
just add this property in Flatlist
scrollEnabled={false}

Change unique item in FlatList using ExtraData

I have on flatList that renders 5 TouchableOpacity. I want to change borderColor from the one I press in my flatList without changing the other, and do it with index that saved in state
<FlatList data={this.state.data} keyExtractor={item => item.id}
numColumns={columns}
renderItem={({ item }) => {
if (item.empty) {
return <View style={[Cards.item, Cards.itemEmpty]} />;
}
return (<View style={[{ flex: 1 }]}>
<TouchableOpacity onPress={() => this.onPressChangeColor(item.id)}
style={[Cards.item, {
backgroundColor: "grey",
borderColor: "grey",
borderWidth: 2
}]}>
<Text style={[{ color: "white", textAlign: 'center', alignSelf: 'center' }]}>{item.name}</Text>
</TouchableOpacity>
</View>);
}
}
/>
You need to find the unique TouchableOpacity:
save the index in state:
state = {
index: null
}
save the unique index inonPressChangeColor function like this:
onPressChangeColor = (id,index) => {
//do what you want with the id
this.setState({index})
}
and the FlatList with some changes:
<FlatList data={this.state.data} keyExtractor={item => item.id}
numColumns={columns}
renderItem={({ item, index }) => {
if (item.empty) {
return <View style={[Cards.item, Cards.itemEmpty]} />;
}
return (<View style={[{ flex: 1 }]}>
<TouchableOpacity onPress={() => this.onPressChangeColor(item.id, index)}
style={[Cards.item, {
backgroundColor: "grey",
borderColor: index == this.state.index ? "green" : "grey",
borderWidth: 2
}]}>
<Text style={[{ color: "white", textAlign: 'center', alignSelf: 'center' }]}>{item.name}</Text>
</TouchableOpacity>
</View>);
}
}
/>

undefined is not a function(evaluating '_this2.AlertButton()')?

I create touchableopacity for every item in map. it works well but when I give function to TouchableOpacity like below, it gives me error which is on title. How can I fix this ?
it gives error when I write this.AlertButton()
{section.subcategory.map((item, key) => (
<View key={key} style={styles.item}>
<TouchableOpacity
onPress={() =>this.AlertButton()}>
</TouchableOpacity>
<View style={styles.separator} />
</View>
))}
This is my alert function :
AlertButton() {
const number = 'TelNo';
Alert.alert(
'',
'Test',
[
{text: 'NO'},
{text: 'Yes', onPress: () => Linking.openURL(`tel:${number}`)},
],
);
}
Here is render. And my map function which is above is in renderContent
render() {
CONTENT2 =[];
CONTENT2 = this.state.fromPage1;
return (
<View style={styles.container}>
<View style={{height: this.state.yuksek, width: this.state.genis, justifyContent: 'center', alignItems: 'center',position:'absolute'}}>
<Text style={{fontWeight: 'bold', color:'#856F6F'}}>Yukarıdaki menü butonlarına tıklayınız.</Text>
</View>
<View style={{height: this.state.yuksek2, width: this.state.genis2, justifyContent: 'center', alignItems: 'center'}}>
<Text style={{fontWeight: 'bold', color:'#856F6F'}}>String</Text>
</View>
<ScrollView contentContainerStyle={{}}>
<Accordion
activeSections={this.state.activeSections}
sections={CONTENT2}
touchableComponent={TouchableOpacity}
expandMultiple={false}
renderHeader={this.renderHeader}
renderContent={this.renderContent}
duration={400}
onChange={this.setSections}
/>
</ScrollView>
<View style={{height:85, width:85,position:'absolute',bottom:5,right:5}}>
<TouchableOpacity style={{flex:1}} onPress={() => this.AlertButton()}>
<ImageBackground source={require('../../image/phoneCall.png')} style={{flex:1}}>
</ImageBackground>
</TouchableOpacity>
</View>
</View>
);
}
}
just change the following line
renderContent={this.renderContent}
to
renderContent={this.renderContent.bind(this)}
because when you are using the class method directly as callback then its not definitely bound to its class when called from inside the component

Styling react native components

When I run following code on my phone
render() {
return [
<View style={{ flex: 1, flexDirection: 'row' }}>
<Search />
</View>,
<View style={{ flex: 1, flexDirection: 'row' }}>
<FlatList
style={styles.list}
data={this.state.products}
renderItem={({ item }) => <ProductCard product={item} />}
keyExtractor={item => item.id}
/>
</View>,
];
}
I am getting screen split between Search and Productcard component. It feels like each one of them takes by default 50% of screen, but I want them to come one after each other.
Search component is just a dummy text:
export default function Search() {
return <Text>Hej</Text>;
}
But when I remove around them it looks good.
are you looking for something like this?
render() {
return(
<View style={{flex: 1, flexDirection: 'column'}}>
<View style={{flexDirection: 'row' }}>
<Search />
</View>,
<View style={{ flex: 1, flexDirection: 'row' }}>
<FlatList
style={styles.list}
data={this.state.products}
renderItem={({ item }) => <ProductCard product={item} />}
keyExtractor={item => item.id}
/>
</View>
</View>
);
}
I suppose you want to make them scroll, if so you have to wrap them around a <ScrollView>.
like so,
render() {
return (
<ScrollView>
<View style={{ flex: 1, flexDirection: 'row' }}>
<Search />
</View>,
<View style={{ flex: 1, flexDirection: 'row' }}>
<FlatList
style={styles.list}
data={this.state.products}
renderItem={({ item }) => <ProductCard product={item} />}
keyExtractor={item => item.id}
/>
</View>
</ScrollView>
);
}
And in second case if you want only the second half to be scrollable just wrap that view inside a <ScrollView> tag.
Thx for helping, it got me in right direction but I got it working by code below:
<View>
<Search />,
<FlatList
style={styles.list}
data={this.state.products}
renderItem={({ item }) => <ProductCard product={item} />}
keyExtractor={item => item.id}
/>
,
</View>