Error with renderItem in React-native Flatlist - react-native

I'm trying to set up a flatlist to test it on a screen in React-native.
When I launch the emulator I'm getting this error : "Can't find variable renderItem" but I don't really know what's wrong with my code. It seemed that I had every element.
Is there someone that can help me ? Thanks a lot for any explanations or answer you can give to help.
import React, { Component } from "react";
import { Header } from "react-native-elements";
import {
FlatList,
SafeAreaView,
StatusBar,
StyleSheet,
Text,
ImageBackground,
View,
ScrollView,
Image,
TouchableOpacity
} from "react-native";
import i18n from "../../src/i18n";
import styles from "../../assets/Styles/Styles";
const DATA = [
{
id: "bd7acbea-c1b1-46c2-aed5-1",
title: "Test 1",
},
{
id: "3ac68afc-c605-48d3-a4f8-2",
title: "Test 2",
},
{
id: "58694a0f-3da1-471f-bd96-3",
title: "Test 3",
},
{
id: "58694a0f-3da1-471f-bd96-4",
title: "Test 4",
},
{
id: "58694a0f-3da1-471f-bd96-5",
title: "Test 5",
},
{
id: "58694a0f-3da1-471f-bd96-6",
title: "Test 6",
},
{
id: "58694a0f-3da1-471f-bd96-7",
title: "Test 7",
},
{
id: "58694a0f-3da1-471f-bd96-8",
title: "Test 8",
},
{
id: "58694a0f-3da1-471f-bd96-9",
title: "Test 9",
},
];
const Item = ({ item, onPress, style }) => (
<TouchableOpacity onPress={onPress} style={[styles.flightsListitem, style]}>
<Text style={styles.h3}>{item.title}</Text>
</TouchableOpacity>
);
export default class FlightsList extends Component {
constructor(props) {
super(props);
this.state = {
selectedId: '',
setSelectedId:''
}
};
renderItem = ({ item }) => {
const backgroundColor = item.id === selectedId ? "transparent" : "fff";
return (
<Item
item={item}
onPress={() => setSelectedId(item.id)}
style={{ backgroundColor }}
/>
);
};
render() {
return (
<ImageBackground
source={require("../../assets/images/background.jpg")}
style={styles.backgroundImage}
>
<Header
backgroundImage={require("../../assets/images/bg-header.png")}
backgroundImageStyle={{
resizeMode: "stretch",
}}
centerComponent={{
text: i18n.t("mytrips.title"),
style: styles.headerComponentStyle,
}}
containerStyle={[styles.headerContainerStyle, { marginBottom: 0 }]}
statusBarProps={{ barStyle: "light-content" }}
/>
<ScrollView style={styles.containerScrollNoMargins}>
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
renderItem={renderItem}
keyExtractor={(item) => item.id}
extraData={selectedId}
/>
<TouchableOpacity
style={styles.touchable2}
onPress={() => this.props.navigation.goBack()}
>
<View style={styles.view2}>
<Text style={styles.textimg2}>
{i18n.t("tripsform.action.back")}
</Text>
</View>
<Image
source={require("../../assets/images/btn-background.png")}
style={styles.tripsimg2}
/>
</TouchableOpacity>
</SafeAreaView>
<Text>{"\n"}</Text>
</ScrollView>
</ImageBackground>
);
};
}

change
renderItem={renderItem}
to
renderItem={this.renderItem}

You must use renderItem={this.renderItem}
Because your renderItem function is not a variable or inner function of your render function. So, you must use this when you're trying to call another function of your class.

Related

Why isn't my FlatList showing in React Native?

I am following a tutorial but as I code along I am stuck,
Why isn't my FlatList not showing?
App.js is simply returning MessagesScreen "screen".
This is my code for a MessagesScreen:
import React from "react";
import { FlatList } from "react-native";
import ListItem from "../components/ListItem";
const messages = [
{
id: 1,
title: "T1",
description: "D1",
image: require("../assets/mosh.jpg"),
},
{
id: 2,
title: "T2",
description: "D2",
image: require("../assets/mosh.jpg"),
},
{
id: 3,
title: "T3",
description: "D3",
image: require("../assets/mosh.jpg"),
},
{
id: 4,
title: "T4",
description: "D4",
image: require("../assets/mosh.jpg"),
},
];
const MessagesScreen = () => {
return (
<FlatList>
data={messages}
keyExtractor={(message) => message.id.toString()}
renderItem=
{({ item }) => {
return (
<ListItem
title={item.title}
subTitle={item.subTitle}
image={item.image}
/>
);
}}
</FlatList>
);
};
export default MessagesScreen;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
This is my component for the ListItem:
import React from "react";
import { View, StyleSheet, Image } from "react-native";
import AppText from "./AppText";
import colors from "../config/colors";
function ListItem({ title, subTitle, image }) {
return (
<View style={styles.container}>
<Image style={styles.image} source={image} />
<View>
<AppText style={styles.title}>{title}</AppText>
<AppText style={styles.subTitle}>{subTitle}</AppText>
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
flexDirection: "row",
},
image: {
width: 70,
height: 70,
borderRadius: 35,
marginRight: 10,
},
subTitle: {
color: colors.medium,
},
title: {
fontWeight: "500",
},
});
export default ListItem;
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
What I've tried is to use the return inside the "renderItem", but with no work, also done it without. The code doesn't give me any errors, so I can't see where the problem is.
You're accessing a property that doesn't exist on your items: subTitle. Did you mean to use description?
Also, I don't believe you can pass in the result of a require call like that. Try passing the raw url and placing the require in the image={} prop instead
Oh it's just a quick fix.
FlatList should be one tag:
const MessagesScreen = () => {
return (
<FlatList // <--- edit here
data={messages}
keyExtractor={(message) => message.id.toString()}
renderItem=
{({ item }) => {
return (
<ListItem
title={item.title}
subTitle={item.subTitle}
image={item.image}
/>
);
}}
/> // <--- and here
);
};
Here's a codesandbox to demonstrate

To call props from an const object in react native/expo

I'm trying to figure out how to use const objects to create 3 categories in my trivia game. I'm defining each one of them like this:
const questions = [
{
question: "Qual o tipo de arquitetura utilizada na Igreja da Madre de Deus?",
answers: [
{ id: "1", text: "Colonial" },
{ id: "2", text: "Maneirista" },
{ id: "3", text: "Gótico" },
{ id: "4", text: "Barroco", correct: true }
]
},
{
question: "No século XIX, o pintor que pintou os painéis da igreja foi:",
answers: [
{ id: "1", text: "Sebastião Canuto da Silva Tavares", correct: true },
{ id: "2", text: "Frans Janszoon Post" },
{ id: "3", text: "Oscar Pereira da Silva" },
{ id: "4", text: "João de Deus Sepúlveda" }
],
quiz_answer: "Esse é o cara!"
}
]
export default questions;
There is a file called IndexQuiz, where I'm calling them through a menu of categories (inside TouchableOpacity):
export default ({ navigation }) => (
<ScrollView>
<SafeAreaView style={{alignItems: "center", flexDirection: "column"}}>
<TouchableOpacity onPress={() =>
navigation.navigate("Quiz", {
title: "Arquitetura",
questions: arquitetura,
color: "rgb(32, 53, 70)"
})}
style={DesafiosStyles.cardContainer}>
</TouchableOpacity>
<TouchableOpacity onPress={() =>
navigation.navigate("Quiz", {
title: "Curiosidades",
questions: curiosidades,
color: "rgb(32, 53, 70)"
})}
style={DesafiosStyles.cardContainer}>
</TouchableOpacity>
<TouchableOpacity onPress={() =>
navigation.navigate("Quiz", {
title: "História",
questions: historia,
color: "rgb(32, 53, 70)"
})}
style={DesafiosStyles.cardContainer}>
</TouchableOpacity>
</SafeAreaView>
</ScrollView>
);
But when it comes to the Quiz file, inside render I have this:
render() {
const questions = this.props.route.params.questions.length;
const question = questions[this.state.activeQuestionIndex];
//console.log(question);
return (
<View
style={[
styles.container,
{ backgroundColor: this.props.route.params.color }
]}
>
<StatusBar barStyle="light-content" />
<SafeAreaView style={styles.safearea}>
<View>
<Text style={styles.text}>{question.question}</Text>
<ButtonContainer>
{answers.map(answer => (
<Button
key={answer.id}
text={answer.text}
onPress={() => this.answer(answer.correct)}
/>
))}
</ButtonContainer>
</View>
<Text style={styles.text}>
{`${this.state.correctCount}/${this.state.totalCount}`}
</Text>
</SafeAreaView>
<Alert
correct={this.state.answerCorrect}
visible={this.state.answered}
/>
</View>
);
}
Every time I try to call any of these categories, I got the "undefined is not an object" exception. I've tried to import the files and the "questions" const itself, but it didn't work. As simple as that must be, I'm stuck in this (yep, I'm kinda slow and basically a newbie with react native lol):
<Text style={styles.text}>{question.question}</Text>
<ButtonContainer>
{answers.map(answer => (
<Button
key={answer.id}
text={answer.text}
onPress={() => this.answer(answer.correct)}
/>
))}
</ButtonContainer>
Without this code, it shows the counter: "this.state.correctCount}/${this.state.totalCount", but that's all. How can I call these questions and answers properly?
I think the problem is that you try to get questions from length property, not from questions object itself:
const questions = this.props.route.params.questions.length;
const question = questions[this.state.activeQuestionIndex];

Add a button "see more" in FlatList?

I use flatList to make a list of elements. I would like to show 15 elements and then add a button "see more" to show the next 15 etc.
I was about tu use this tutorial : https://aboutreact.com/react-native-flatlist-pagination-to-load-more-data-dynamically-infinite-list/
But I don't need to use fetch, I already have set up the data (state.listData) and in fact, I'm a little lost on how to adapt it...
I thought that maybe anyone could help me a little.
Thanks a lot
this.state = {
selectedId: '',
setSelectedId:'',
listData:''
}
};
renderItem = ({ item }) => {
const backgroundColor = item.id === this.selectedId ? "transparent" : "fff";
return (
<View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
<Item
item={item}
onPress={() => this.props.navigation.navigate('UpdateTripsForm')}
style={{ backgroundColor }}
/>
<Image source={require("../../assets/images/arrow.png")} style={{width: 15, height:15, justifyContent: 'center'}}/>
</View>
);
};
initListData = async () => {
let list = await getFlights(0);
if (list) {
this.setState({
listData: list
});
}
};
render() {
return (
<SafeAreaView style={styles.container}>
<FlatList
data={this.state.listData}
renderItem={this.renderItem}
maxToRenderPerBatch={15}
keyExtractor={(item) => item.id}
extraData={this.selectedId}
/>
<TouchableOpacity
style={styles.touchable2}
onPress={() => this.props.navigation.goBack()}
>
<View style={styles.view2}>
<Text style={styles.textimg2}>
{i18n.t("tripsform.action.back")}
</Text>
</View>
<Image
source={require("../../assets/images/btn-background.png")}
style={styles.tripsimg2}
/>
</TouchableOpacity>
</SafeAreaView>
);
};
}
I just tried this thanks to #Pramod 's answer :
const Item = ({ item, onPress, style }) => (
<TouchableOpacity onPress={onPress} style={[styles.flightsListitem, style]}>
<Text style={styles.h4}>{item.id}</Text>
</TouchableOpacity>
);
export default class FlightsList extends Component {
constructor(props) {
super(props);
this.state = {
selectedId: '',
setSelectedId:'',
listData:'',
page:1,
perPage:2,
loadMoreVisible:true,
displayArray:[]
}
};
renderItem = ({ item }) => {
const backgroundColor = item.id === this.selectedId ? "transparent" : "fff";
return (
<View style={{flexDirection: 'row', justifyContent: 'space-between', alignItems: 'center'}}>
<Item
item={item}
onPress={() => this.props.navigation.navigate('UpdateTripsForm')}
style={{ backgroundColor }}
/>
<Image source={require("../../assets/images/arrow.png")} style={{width: 15, height:15, justifyContent: 'center'}}/>
</View>
);
};
initListData = async () => {
let list = await getFlights(0);
if (list) {
this.setState({
listData: list
});
}
};
componentDidMount(){
this.setNewData()
// console.log(tempArray)
}
setNewData(){
var tempArray=[]
if(this.state.listData.length == this.state.displayArray.length){
this.setState({
loadMoreVisible:false
})
}else{
for(var i=0; i<(this.state.page*this.state.perPage); i++){
tempArray.push(this.state.listData)
}
this.setState({
displayArray: tempArray,
loadMoreVisible:true
})
}
}
loadMore(){
this.setState({
page: this.state.page+1
},()=>{
this.setNewData()
})
}
async UNSAFE_componentWillMount() {
this.initListData();
}
render() {
return (
<ImageBackground
source={require("../../assets/images/background.jpg")}
style={styles.backgroundImage}
>
<Header
backgroundImage={require("../../assets/images/bg-header.png")}
backgroundImageStyle={{
resizeMode: "stretch",
}}
centerComponent={{
text: i18n.t("mytrips.title"),
style: styles.headerComponentStyle,
}}
containerStyle={[styles.headerContainerStyle, { marginBottom: 0 }]}
statusBarProps={{ barStyle: "light-content" }}
/>
<SafeAreaView style={styles.container}>
<FlatList
data={this.state.displayArray}
renderItem={this.renderItem}
keyExtractor={(item) => item.id}
extraData={this.selectedId}
/>
{this.state.loadMoreVisible == true?
<Button style={{width:'100%', height:10, backgroundColor:'green', justifyContent:'center', alignItems:'center'}}
title = 'load more'
onPress={()=>{this.loadMore()}}>
</Button>:null}
<TouchableOpacity
style={styles.touchable2}
onPress={() => this.props.navigation.goBack()}
>
<View style={styles.view2}>
<Text style={styles.textimg2}>
{i18n.t("tripsform.action.back")}
</Text>
</View>
<Image
source={require("../../assets/images/btn-background.png")}
style={styles.tripsimg2}
/>
</TouchableOpacity>
</SafeAreaView>
</ImageBackground>
);
};
}
the flatlist is not displayed : I get :
You can user pagination method with per page limit so that you can have granular control
Load the array per page when component mount
On every click increase the per page and based on per page update data of your flat list
And also put a flag which will check when the data has ended which will help to hide the load more button when data ends
Working example: https://snack.expo.io/#msbot01/suspicious-orange
import React, { Component } from 'react';
import {
StyleSheet,
Text,
View,
SafeAreaView,
SectionList,
Switch,
FlatList
} from 'react-native';
import Constants from 'expo-constants';
import Icon from 'react-native-vector-icons/FontAwesome';
import AwesomeIcon from 'react-native-vector-icons/FontAwesome';
// or any pure javascript modules available in npm
import { Card } from 'react-native-paper';
export default class App extends Component<Props> {
constructor(props) {
super(props);
this.state = {
page:1,
perPage:2,
loadMoreVisible:true,
DATA: [{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'fourth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'fifth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29sd72',
title: 'sixth Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29dr72',
title: 'seventh Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d7w2',
title: 'Eight Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29ad72',
title: 'Nineth Item',
},
{
id: '58694a0f-3da1-471f-bd96-14557d1e29d72',
title: 'Tenth Item',
}],
displayArray:[]
}
}
componentDidMount(){
this.setNewData()
// console.log(tempArray)
}
setNewData(){
var tempArray=[]
if(this.state.DATA.length == this.state.displayArray.length){
this.setState({
loadMoreVisible:false
})
}else{
for(var i=0; i<(this.state.page*this.state.perPage); i++){
tempArray.push(this.state.DATA[i])
}
this.setState({
displayArray: tempArray,
loadMoreVisible:true
})
}
}
loadMore(){
this.setState({
page: this.state.page+1
},()=>{
this.setNewData()
})
}
render() {
return (
<View style={{ flex: 1 }}>
<FlatList
data={this.state.displayArray}
renderItem={({item})=>
<View style={{flexDirection:'row'}}>
<Text style={{fontSize:20}}>{item.title} </Text>
</View>
}
keyExtractor={item => item.id}
/>
{this.state.loadMoreVisible == true?
<View style={{width:'100%', height:10, backgroundColor:'green', justifyContent:'center', alignItems:'center'}} onClick={()=>{this.loadMore()}}>Load more</View>:null
}
</View>
);
}
}
Set data in state (already done ==> this.state.listData)
Set counter in state (initialize with 1)
Set 15 first elements in state (you can name it "renderedData" or something like that) and then increase cuonter to 1
Add a function that increases the "renderedData" by 15 items by increasing the counter by one
Add Footer component to the list which will call the function you created in stage 3
To take only 15( or 30/45/60 etc..) items from the list you can do something like this:
this.setState({ renderedItem: listData.slice(0, counter*15) })

Rendering items not showing up

im writing a todolist with reactnative using hooks , however when rendering todo items , its not showing up, any advice to fix this
thank you so much for your help!!!
import React, { useState } from 'react';
import { StyleSheet, FlatList, Text, View } from 'react-native';
export default function App() {
const [todos, setTodos] = useState([
{ text: 'budddy', key: '1' },
{ text: 'helloddd', key: '2' },
{ text: "hellddo", key: '3' }
])
return (
<View style={styles.container} >
<View style={styles.content}>
<FlatList data={todos} renderItem={({ item }) => {
<Text> {item.text}</Text>
}} />
</View>
</View>
);
}
const styles = StyleSheet.create({
container: {
paddingTop: 30,
},
content: {
padding: 40
},
})
Check the renderItem code you need to add return or use the implicit return of arrow function
<FlatList data={todos} renderItem={({ item }) => (
<Text> {item.text}</Text>
)} />
Use the extraData property on your FlatList component.
As per documentation:
Bypassing extraData={this.state} to FlatList we make sure FlatList will re-render itself when the state.selected changes. Without setting this prop, FlatList would not know it needs to re-render any items because it is also a PureComponent and the prop comparison will not show any changes.
here is the example code (documentation)
import React from 'react';
import {
SafeAreaView,
TouchableOpacity,
FlatList,
StyleSheet,
Text,
} from 'react-native';
import Constants from 'expo-constants';
const DATA = [
{
id: 'bd7acbea-c1b1-46c2-aed5-3ad53abb28ba',
title: 'First Item',
},
{
id: '3ac68afc-c605-48d3-a4f8-fbd91aa97f63',
title: 'Second Item',
},
{
id: '58694a0f-3da1-471f-bd96-145571e29d72',
title: 'Third Item',
},
];
function Item({ id, title, selected, onSelect }) {
return (
<TouchableOpacity
onPress={() => onSelect(id)}
style={[
styles.item,
{ backgroundColor: selected ? '#6e3b6e' : '#f9c2ff' },
]}
>
<Text style={styles.title}>{title}</Text>
</TouchableOpacity>
);
}
export default function App() {
const [selected, setSelected] = React.useState(new Map());
const onSelect = React.useCallback(
id => {
const newSelected = new Map(selected);
newSelected.set(id, !selected.get(id));
setSelected(newSelected);
},
[selected],
);
return (
<SafeAreaView style={styles.container}>
<FlatList
data={DATA}
renderItem={({ item }) => (
<Item
id={item.id}
title={item.title}
selected={!!selected.get(item.id)}
onSelect={onSelect}
/>
)}
keyExtractor={item => item.id}
extraData={selected}
/>
</SafeAreaView>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
marginTop: Constants.statusBarHeight,
},
item: {
backgroundColor: '#f9c2ff',
padding: 20,
marginVertical: 8,
marginHorizontal: 16,
},
title: {
fontSize: 32,
},
});

changing text in Flatlist for each item

Hey guys I would like to know how to change text in each row of a Flatlist.
I want to be able to toggle between follow and unfollow.
Here's my code example :=>
this.state = {
FlatListItems : [
{"key": "MARIA", "image":require("./assets/image/maria.jpg")},
{"key": "MARTA", "image":require("./assets/image/marta.jpg")},
{"key": "MARTIN", "image":require("./assets/image/martin.jpg") },
{"key": "OLIVIA", "image":require("./assets/image/olivia.jpg") },
],
checked:true,
}'
And here's the checked function
checked=()=>{
if(checked==true)
{
this.checked.setState(true)
}
else{
this.checked.setState(False)
}
}
And here's the render function
<FlatList
contentContainerStyle={{
flexDirection: 'row',alignItems:'center',paddingLeft:10,borderTopRightRadius:10,borderTopLeftRadius:10,
flexWrap: 'wrap',}}
data={ this.state.FlatListItems }
ItemSeparatorComponent = {this.FlatListItemSeparator}
renderItem={({item,key}) =><View style={{padding:5,borderTopRightRadius:10,borderTopLeftRadius:10,}}>
<ImageBackground source={item.image}
style={{height:230,width:185,borderTopRightRadius:10,borderTopLeftRadius:10}}
blurRadius={ Platform.OS == 'ios' ? 10 : 6 } >
<View style={{alignItems:'center',padding:20,backgroundColor:'rgba(0,0,12, 0.4)'}}>
<View style={{alignItems:'center',padding:20}}>
<Image source={item.image} style={{width: 90, height: 90, borderRadius: 60}}/>
</View>
<View style={{alignItems:'center',paddingTop:10}}>
<Text style={{fontSize:18,fontFamily:'CRC55',color:'white'}}>{item.key}</Text>
<Text style={{fontSize:22,fontFamily:'CRC55',color:'white',paddingTop:10}}>{item.key}</Text>
<View style={{backgroundColor:'white',width:185,height:10}}>
</View>
</View>
</View>
</ImageBackground>
{
!this.state.checked? <TouchableOpacity onpress={this.checked}
><Text style={{fontSize:20,alignItems:'center'}}>FOLLOWING</Text></TouchableOpacity>: <TouchableOpacity onpress={()=>{this.setState({checked:key})}}><Text style={{fontSize:20,alignItems:'center'}}>FOLLOW</Text></TouchableOpacity>
}
</View>
}
/>
My question is how can I toggle between follow and unfollow for each item in the Flatlist.
You can use directly this example. I have just used some code from offical docs. You keep each list item state separately. You can adjust this code easily for your needs
import React, { Component } from 'react'
import { Text, View, FlatList, TouchableOpacity } from 'react-native'
const data = [
{ "key": "MARIA", "title": "image MARIA", "id": 1 },
{ "key": "MARTIN", "title": "image MARTIN", "id": 2 },
{ "key": "OLIVIA", "title": "image OLIVIA", "id": 3 },
];
class MyListItem extends React.PureComponent {
state = {
selected: true
}
_onPress = () => {
this.setState({
selected: !this.state.selected
})
};
render() {
const text = this.state.selected ? "follow" : "unfollow";
return (
<TouchableOpacity onPress={this._onPress}>
<View>
<Text >
{this.props.title + " " + text}
</Text>
</View>
</TouchableOpacity>
);
}
}
export default class MultiSelectList extends React.PureComponent {
_keyExtractor = (item, index) => item.id;
_renderItem = ({ item }) => (
<MyListItem
id={item.id}
title={item.title}
/>
);
render() {
return (
<FlatList
data={data}
extraData={this.state}
keyExtractor={this._keyExtractor}
renderItem={this._renderItem}
/>
);
}
}