I am using a list of image.Below every image,there is a like button. When i click on the Like button, likes should be increases which is working fine. But it should work on the image I click. Currently it is increasing like count of all the images.I am new to react native.Any help would be appreciated.
Here, this is my code
export default class Art extends Component {
constructor(props) {
super(props)
this.state = {
value: null,
liked:false
}
}
_increaseValue(){
console.log(this.state.liked)
if (this.state.liked==false)
{
this.setState({liked: !this.state.liked})
newvalue =this.state.value +1;
this.setState({value:newvalue})
}
else
{
this.setState({liked: !this.state.liked})
newvalue =this.state.value -1;
this.setState({value:newvalue}
}
}
render() {
const datas = [
{
img: images[0]
},
{
img: images[1]
},
{
img: images[2]
},
{
img: images[3]
},
];
const { navigate } = this.props.navigation;
// eslint-disable-line
return (
<Content padder style={{ marginTop: 0, backgroundColor: '#3b5998' }}>
<List
style={{ marginLeft: -19, marginRight: -19 }}
dataArray={datas}
renderRow={data =>
<ListItem >
<Card
wrapperStyle={{ marginLeft: -10, marginTop: -10, marginRight: -10, }} containerStyle={{ marginLeft: 2, marginTop: -5, }}>
<TouchableOpacity activeOpacity={.5} onPress={() => navigate('ImageDisplay',{item:data})}>
<Image source={{ uri: data.img }} style={[styles.imageContainer, styles.image]}/>
</TouchableOpacity>
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-around', marginTop: 20 }}>
<View style={{flexDirection:'row'}}>
<TouchableOpacity activeOpacity={.5} onPress={() => {this._increaseValue()}}>
<View>
{this.state.liked ? <Icon active name="favorite" style={styles.iconCountContainer} color='red' size={14}/>
: <Icon name="favorite" style={styles.iconCountContainer} size={14}/>}
</View></TouchableOpacity>
<Text style={{color:'#000000',fontSize:15, marginLeft:12, marginTop:5}}>{this.state.value} Likes </Text>
</View>
<View style={styles.iconCountContainer}>
<Icon active name="share" size={14} style={styles.share} onPress={() => Share.open(shareOptions).catch((err) => { err && console.log(err); })} />
</View>
</View>
</Card>
</ListItem>
}
/>
</Content>
);
}
}
You need to convert your Cards into separate components or store the like counts separately in state. You can approach this problem several ways. I'll give you an example of how you can achieve this behavior and you can implement it the way you like.
Example
export default class CutomListItem extends React.Component {
constructor(props) {
this.state = {
likes: 0
};
}
_increaseValue = () => {
this.setState((prevState) => {
return {
likes: prevState.likes++
};
});
}
render() {
const { data, navigate, share } = this.props; // send data with props
<ListItem >
<Card
wrapperStyle={{ marginLeft: -10, marginTop: -10, marginRight: -10, }} containerStyle={{ marginLeft: 2, marginTop: -5, }}>
<TouchableOpacity activeOpacity={.5} onPress={() => navigate('ImageDisplay',{item:data})}>
<Image source={{ uri: data.img }} style={[styles.imageContainer, styles.image]}/>
</TouchableOpacity>
<View style={{ flexDirection: 'row', alignItems: 'center', justifyContent: 'space-around', marginTop: 20 }}>
<View style={{flexDirection:'row'}}>
<TouchableOpacity activeOpacity={.5} onPress={() => {this._increaseValue()}}>
<View>
{this.state.liked ? <Icon active name="favorite" style={styles.iconCountContainer} color='red' size={14}/>
: <Icon name="favorite" style={styles.iconCountContainer} size={14}/>}
</View></TouchableOpacity>
<Text style={{color:'#000000',fontSize:15, marginLeft:12, marginTop:5}}>{this.state.likes} Likes </Text>
</View>
<View style={styles.iconCountContainer}>
<Icon active name="share" size={14} style={styles.share} onPress={() => Share.open(shareOptions).catch((err) => { err && console.log(err); })} />
</View>
</View>
</Card>
</ListItem>
}
}
return (
<Content padder style={{ marginTop: 0, backgroundColor: '#3b5998' }}>
<List
style={{ marginLeft: -19, marginRight: -19 }}
dataArray={datas}
renderRow={data => (<CutomListItem data={data} navigate={navigate} share={Share} />}
/>
</Content>
);
}
Related
I'm developing a food ordering app using react native and ASP .NET MVC Entity Framework.
I've Search screen with date(field) and vendor list(dropdown) and when I click on search button it will navigate to Orders Screen with date and vendor Id as parameters and with these 2 parameter I fetch data from API and show data with in Orders screen. But problem is first time it's showing correct list and 2nd time with different date and vendor id not updating list in Orders screen while API fetching correct data and showing previous data.
Search Screen Code
<View style={[styles.container, { backgroundColor: colors.background }]}>
<StatusBar style={theme.dark ? "light" : "dark"} />
<CustomLoading isLoading={isLoading} />
{/* Header */}
<View style={styles.header}>
<Animatable.View animation="bounceIn" duration={2000}>
<Image style={styles.logo} source={images.FinalLogoOnLight} />
</Animatable.View>
<Animatable.Text
animation="bounceInLeft"
duration={2000}
style={[styles.screenTitle, { color: colors.black }]}
>
Search/Filter Receipts
</Animatable.Text>
</View>
{/* Form */}
<View>
{/* Date */}
<TouchableOpacity
style={[styles.datePickerWrapper, { backgroundColor: colors.white }]}
onPress={showDatePicker}
>
<DateTimePickerModal
isVisible={isDatePickerVisible}
mode="date"
value={model.date}
onConfirm={handleConfirm}
onCancel={hideDatePicker}
/>
<Text style={{ color: colors.black, fontFamily: "PoppinsRegular" }}>
{moment(model.date).format("YYYY-MM-DD")}
</Text>
<AntDesign name="calendar" color={colors.gray} size={sizes.h2} />
</TouchableOpacity>
{/* DropDown */}
{/* <FormDropDown dropDownRef={dropDownRef} options={vendors} /> */}
<View
style={[
styles.dropDownWrapper,
{
flexDirection: "row",
marginTop: sizes.m10,
justifyContent: "center",
alignItems: "center",
backgroundColor: colors.white,
borderColor: colors.grayLight,
},
]}
>
{model.vendors != null ? (
<FormPicker
placeholderText="Select Vendor"
selectedValue={model.vendorUserId}
onValueChange={(val) => setModel({ ...model, vendorUserId: val })}
data={model.vendors}
/>
) : null}
</View>
{/* Search Button */}
<FormButton
mystyle={{ marginTop: sizes.m20 }}
buttonTitle="Search"
onPress={() => handleSubmit()}
/>
</View>
const handleSubmit = async () => {
try {
if (model.vendorUserId == "" && model.date == "") {
Toast.show("Date or Vendor filed not be empty.");
return;
}
navigation.navigate("RootOrder", {
screen: "SearchedOrders",
params: { searchedOrders: model },
});
} catch (error) {
console.log(error);
setIsLoading(false);
}
};
Searched Order Screen
const [isLoading, setIsLoading] = useState(true);
const [start, setStart] = useState(0);
const [model, setModel] = useState({
data: [],
token: userState.token,
date: searchedOrders.date,
vendorUserId: searchedOrders.vendorUserId,
recordTotal: null,
});
// Functions
const fetchOrderHistoryByDate = async () => {
try {
setIsLoading(true);
var res = await orderHistoryByDate(model);
if (!res.Success) {
console.log("Error: ", res.Data);
setIsLoading(false);
alert(res.Data);
return;
}
var resModel = res.Data;
// console.log(resModel)
setModel({ ...model, data: resModel });
// console.log(resModel);
setIsLoading(false);
} catch (error) {
console.log(error);
setIsLoading(false);
}
};
// Functions END
const init = async () => {
await fetchOrderHistoryByDate();
setIsLoading(false);
};
useEffect(() => {
const unsubscribe = navigation.addListener("focus", () => {
setStart(Math.random() * 10000);
init();
});
return unsubscribe;
}, [start]);
function renderCardItems({ item, index }) {
return (<View style={styles.OrderItemWrapper}>
<LinearGradient
style={[styles.OrderItemWrapperLinearGrad]}
colors={[colors.white, colors.linearGray]}
>
<TouchableOpacity
// style={[styles.OrderItemWrapper, { backgroundColor: colors.white }]}
onPress={() =>
navigation.navigate("OrderDetails", { itemOrderDetails: item })
}
// key={index}
>
<View style={styles.cartItemWrapper}>
<View style={styles.cartItemDetails}>
<Text style={[styles.cartItemText, { color: colors.primary }]}>
{item.ShopName}
{/* ({index}) */}
</Text>
{/* <Text style={{ color: "#000" }}>{item.InvoiceNo}</Text> */}
<Text
style={[styles.cartItemQuantityText, { color: colors.gray }]}
>
{item.Date}
</Text>
<View
style={{
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
}}
>
<Text
style={[styles.cartItemPriceText, { color: colors.black }]}
>
AED {item.Total}
</Text>
<View
style={[
styles.statusWrapper,
{ backgroundColor: colors.primary },
]}
>
<Text style={[styles.statusText, { color: colors.white }]}>
{item.Status}
</Text>
</View>
</View>
</View>
<Image
source={{
uri: `${domain}${item.ShopPicture}`,
}}
style={styles.cardItemImage}
/>
</View>
</TouchableOpacity>
</LinearGradient>
</View>);
}
return (
<View style={[styles.container, { backgroundColor: colors.background }]}>
<StatusBar style={theme.dark ? "light" : "dark"} />
<CustomLoading isLoading={isLoading} />
<FlatList
data={model.data}
renderItem={renderCardItems}
keyExtractor={(item, index) => item.InvoiceNo + "_" + index}
showsHorizontalScrollIndicator={false}
showsVerticalScrollIndicator={false}
style={{ marginTop: sizes.m10 }}
style={{
paddingVertical: sizes.m10,
backgroundColor: colors.background,
}}
/>
</View>
you can use navigation.push('screanName') instead of navigation.navigate('screenName')
ListHeaderComponent inside flatlist doesn't work. It won't render nothing in header (above flatlist). If I however put some custom component it does work but it doesn't with my renderHeader function. I tried making a custom component with the same view as in renderHeader but when I used that nothing rendered so I don't know
My flatlist along with whole render:
render() {
const { height } = Dimensions.get("window");
return (
<View style={{flex: 1,
backgroundColor: "#EBECF4"}}>
{/* <Text>
Connection Status :{" "}
{this.state.connection_status ? "Connected" : "Disconnected"}
</Text> */}
{/* <Loader loading={this.state.loading} /> */}
<StatusBar backgroundColor="#63003d" barStyle="light-content" />
<SafeAreaView>
<ModernHeader
backgroundColor="#63003d"
height={50}
text="Eleph"
textStyle={{
color: "white",
fontFamily: "Lobster-Regular",
//fontWeight: "bold",
fontSize: 25,
}}
leftIconComponent={
<TouchableOpacity
style={{ marginRight: 0, margin: 0 }}
onPress={() =>
this.props.navigation.dispatch(DrawerActions.openDrawer())
}
>
<FontAwesome5 name="bars" size={22} color="white" />
</TouchableOpacity>
}
rightIconComponent={
<TouchableOpacity
style={{ marginLeft: 0, margin: 0 }}
onPress={() => this.props.navigation.navigate("Profile")}
>
{/* <MaterialCommunityIcons
name="chart-areaspline"
size={24}
color="#639dff"
/> */}
<Foundation name="graph-bar" size={24} color="white" />
{/* <FontAwesome name="bar-chart" size={24} color="white" /> */}
</TouchableOpacity>
}
/>
</SafeAreaView>
<FlatList
//contentInset={{ top: HEADER_HEIGHT }}
//contentOffset={{ y: -HEADER_HEIGHT }}
data={this.state.post}
extraData={this.state.post}
keyExtractor={(item) => item.id.toString()}
style={{
marginHorizontal: 0,
marginVertical: 6,
}}
renderItem={({ item }) => this.renderPost(item)}
ListFooterComponent={this.renderFooter}
ListHeaderComponent={this.renderHeader}
refreshControl={
<RefreshControl
style={{ color: "#639dff" }}
tintColor="#639dff"
titleColor="#fff"
refreshing={this.state.isLoading}
onRefresh={this.onRefresh}
/>
}
initialNumToRender={7}
onEndReachedThreshold={0.1}
showsVerticalScrollIndicator={false}
onEndReached={() => {
if (
!this.onEndReachedCalledDuringMomentum &&
!this.state.isMoreLoading
) {
this.getMore();
}
}}
onMomentumScrollBegin={() => {
this.onEndReachedCalledDuringMomentum = false;
}}
onScroll={(e) => {
scrollY.setValue(e.nativeEvent.contentOffset.y);
}}
></FlatList>
{/* <View style={styles.footer}>
<TouchableOpacity
activeOpacity={0.9}
onPress={this.getMore}
style={styles.loadMoreBtn}
>
<Text style={styles.btnText}>See more moods</Text>
{this.state.loading ? (
<ActivityIndicator color="white" style={{ marginLeft:8 }} />
) : null}
</TouchableOpacity>
</View> */}
</SafeAreaView>
</View>
My renderHeader function:
renderHeader = () => {
return (
<View
style={{
flex: 1,
flexDirection: "row",
backgroundColor: "#ffffff",
//width: "100%",
padding: 11,
alignItems: "center",
position: "absolute",
justifyContent: "center",
//top: 50,
//bottom: 0,
//left: 0,
//elevation: 4,
//right: 0,
//height: 50,
}}
//flexDirection: "row",
//backgroundColor: "#ffffff",
//width: "100%",
//padding: 11,
//alignItems: "center",
>
<TouchableOpacity
onPress={() => this.props.navigation.navigate("Post")}
>
<Text
style={{ alignItems: "center", color: "#C4C6CE" }}
//placeholder={How are you feeling right now ${this.state.user.name}?}
multiline
>{Tell us how are you feeling right now ${this.state.user.name}?}</Text>
</TouchableOpacity>
{/* <View style={styles.divider}></View> */}
</View>
);
}
Why for example renderFooter works??
renderFooter = () => {
if (!this.state.isMoreLoading) return true;
return (
<ActivityIndicator
size="large"
color={"#D83E64"}
style={{ marginBottom: 10 }}
/>
);
};
Use ListHeaderComponentStyle to style the ListHeaderComponent.
I created a simple snack for you, check if this helps. Your code looks okay but not sure about the whole screen design. Here is my snack link.
https://snack.expo.io/#saad-bashar/excited-fudge
It might be related to the other components inside your screen. So first check only with flatlist, remove all other components. Hope you can sort it out :)
The solution is to remove the "absolute" style in the header for flatlist. The question is mine im just answering with different account but this is the solution that worked.
Hi how can I access the state where I'm fetching all the data in an other component ? I have a component Accueil where I'm fetching the data and a component UserItem where I'm styling and showing the info. So I'm in my Accueil component I have a flatlist and inside this flatlist in the renderItem function I'm passing the . So how can I access the state dataSource in UserItem ?
class UserItem extends React.Component {
render() {
const user = this.props.user;
const displayDetailForUser = this.props.displayDetailForUser;
var colorConnected;
if (user.Statut == "ON") {
colorConnected = "#1fbc26";
}
else if (user.Statut == "OFF") {
colorConnected = "#ff0303";
}
else {
colorConnected = "#ffd200";
}
return (
<TouchableOpacity style={styles.view_container} onPress={() =>
displayDetailForUser(user.MembreId, user.Pseudo, user.Photo, user.Age, user.Genre, user.Description, user.distance, user.Statut, user.localisation, user.principale )}>
<ImageBackground source={{ uri : user.Photo}} style={{ flex: 1, aspectRatio: 1, position: 'relative', borderColor: '#d6d6d6', borderWidth: 1}}>
<View style={[styles.bulle_presence, { backgroundColor: colorConnected } ]}></View>
<TouchableOpacity>
<Image style = {{aspectRatio:0.6, position:'absolute', resizeMode:'contain', height:40, width:40, right:15, top:15 }} source = {require("../Images/chat-bg.png")}/>
</TouchableOpacity>
</ImageBackground>
<View style={{ backgroundColor: '#d6d6d6', padding: 6 }}>
<View style={{ flexDirection: 'row', alignItems: 'center' }}>
<View>
<Text style={{ fontSize: 25 }}>{user.Age}</Text>
</View>
<View style={{ marginRight: 7, marginLeft: 7, backgroundColor: '#000000', width: 1, height: 26 }}></View>
<View style={{ flexDirection: 'column', flex:1 }}>
<Text style={{ fontSize: 13, fontWeight: '600' }}>{user.Pseudo}</Text>
<View style={{ flexDirection: 'row', justifyContent: 'space-between'}}>
<Text style={{ fontSize: 12 }}>{user.distance}</Text>
<Text style={{ fontSize: 12 }}>{user.Genre}</Text>
</View>
</View>
</View>
</View>
</TouchableOpacity>
)
}
}
I've tried with const user = this.props.dataSource but it's not working. Thanks
Edit:
lass Accueil extends React.Component {
constructor(props) {
super(props);
this.state = {
loading: false,
refreshing: false,
location: null,
latitude:null,
longitude:null,
dataSource:[]
}
this.displayPosition = this.displayPosition.bind(this);
}
handleRefresh = () => {
this.setState (
{
refreshing: true,
},
() => {
setTimeout(() => {this.setState({refreshing: false,})}, 1000)
}
);
};
componentDidMount() {
const url = "SomeUrl";
fetch(url)
.then(res => res.json())
.then(res => {
this.setState({
dataSource: res
});
})
.catch(error => {
console.log("get data error:" + error);
});
}
static navigationOptions = ({ navigation }) => {
return {
headerRight: () => (
<View style={{marginLeft: 8, marginRight: 8, flexDirection: 'row', alignItems: 'center' }}>
<TouchableOpacity style={{ marginRight: 10 }} onPress={ () =>{ }}>
<Image style={{ width: 22, height: 22 }} source={require("../Images/search.png")} />
</TouchableOpacity>
<TouchableOpacity style={{marginLeft: 10, marginRight: 10 }} onPress={ () =>{{this.displayPosition()}}}>
<Image style={{ width: 22, height: 22 }} source={require("../Images/localisation.png")} />
</TouchableOpacity>
<TouchableOpacity style={{marginLeft: 10 }} onPress={ () =>{ }}>
<Image style={{ width: 22, height: 22 }} source={require("../Images/refresh.png")} />
</TouchableOpacity>
</View>
),
};
};
displayPosition = () => {
Geolocation.getCurrentPosition(
(position) => {
this.setState({
latitude: JSON.stringify(position.coords.latitude),
longitude: JSON.stringify(position.coords.longitude),
error: null,
});
console.log(this.state.latitude)
},
(error) => this.setState({ error: error.message }),
{ enableHighAccuracy: true, timeout: 20000, maximumAge: 1000 },
);
}
_displayDetailForUser = (idUser, name, photo, age, pratique, description, distance, Statut, localisation, principale ) => {
//console.log("Display user with id " + idUser);
this.props.navigation.navigate("UserProfil", { idUser: idUser, name:name, photo: photo, age:age, pratique:pratique, description:description, distance:distance, Statut:Statut, localisation:localisation, principale:principale });
}
render() {
return (
<SafeAreaView style={{ flex:1 }}>
<View style={styles.main_container}>
<FlatList style={styles.flatList}
data={this.state.dataSource}
keyExtractor={(item) => item.MembreId}
renderItem={() => <UserItem user={this.state.dataSource} displayDetailForUser={this._displayDetailForUser} />}
numColumns={numColumns}
refreshing={this.state.refreshing}
onRefresh={this.handleRefresh} />
</View>
</SafeAreaView>
)
}
}
I want to be able to align all reply icons to the far right, where the red line is, regardless of where they start.
Edit: added more information to show how recursion is used in the component. Why I try to use some answers that work without recursion, I receive an undesired effect.
This is the code I have in place so far:
class Comment extends Component {
render() {
return(
<View>
<Header
rounded
style={{
backgroundColor: '#ffffff',
position: 'relative',
}}
>
<View style={{flexDirection: 'row', flexWrap: 'wrap', right: '43%', top: '50%'}}>
<Icon name='chevron-left' size={10} color='#006FFF' style={{top: '6%'}}/>
<NativeText
onPress={() => this.props.history.push('/')}
style ={{color: '#006FFF', fontSize: 12, fontFamily: 'Montserrat-Regular'}}
>
Back
</NativeText>
</View>
</Header>
<View
style={{paddingLeft: '2%', paddingTop: '2%'}}
>
<CommentList
options={this.props.location.state.comments}
currentUser={this.props.location.state.currentUser}
history={this.props.history}
reportId={this.props.location.state.reportId}
optionsForBackButton={this.props.location.state.comments}
/>
</View>
</View>
)
}
}
export default withRouter(Comment)
const CommentList = ({options, currentUser, history, reportId, optionsForBackButton}) => {
return (
<View>
{options.map(option => (
<View
style={{flexDirection: 'row'}}
>
<NativeText
style={{fontSize: 12, fontFamily: 'Montserrat-Regular'}}
>
{option.content}
</NativeText>
<View
style={{flex: 1, alignItems: 'flex-end' }}
>
<Icon
name='reply'
size={12}
// onPress={() => {
// setModalVisible(true)
// changeParentId(option._id)
// }}
onPress={() => history.push({pathname: '/create-comment', state: {content: option.content, currentUser: currentUser, reportId: reportId, parentCommentId: option._id, optionsForBackButton: optionsForBackButton}})}
/>
</View>
{
<View
style={{left: '10%'}}
>
<CommentList
options={option.reply}
optionsForBackButton={optionsForBackButton}
history={history}
currentUser={currentUser}
reportId={reportId}
/>
</View>
}
</View>
))}
</View>
)
}
Set your icon containing view's flex value to 1. This should cause it to fill all remaining space.
See the following snack: https://snack.expo.io/#jrdndncn/playful-churros
class Comment extends React.Component {
render() {
return (
<View
style={{
marginVertical: 2,
flexDirection: 'row',
marginLeft: (this.props.indent || 0) * 20,
}}>
<Text>{this.props.text}</Text>
<View style={{ flex: 1, alignItems: 'flex-end' }}>
<View style={{ width: 20, height: 20, backgroundColor: 'red' }} />
</View>
</View>
);
}
}
<Comment text="hello" indent={0} />
<Comment text="hello" indent={1} />
<Comment text="hello" indent={2} />
Basically marginLeft:'auto' will do the trick. just add style to icon as :
<Icon
name='reply'
size={12}
style={{marginLeft:'auto'}}
// onPress={() => {
// setModalVisible(true)
// changeParentId(option._id)
// }}
onPress={() => history.push({pathname: '/create-comment', state: {content: option.content, currentUser: currentUser, reportId: reportId, parentCommentId: option._id, optionsForBackButton: optionsForBackButton}})}
/>
i added marginLeft:'auto' in style it will automatically shown at the right end of the screen.
I am using <FlatList/> to render an item for each object of json. This json is stored in this.state.json. Here is my code:
export class MyAppsName extends React.Component {
static navigationOptions = {
title: "App name",
headerLeft: null,
};
constructor() {
super();
this.state = {
index: 0,
isAuthed: false,
data: [
{
name: "Class 1",
grade: 83,
letterGrade: "A+"
},
{
name: "Class 2",
grade: 90,
letterGrade: "B+"
}
],
loading: false
};
}
refresh() {
this.setState({ isAuthed: true });
}
componentWillMount() {
}
render() {
return (
<Root>
<ScrollableTabView initialPage={0} tabBarPosition="top">
<HomeRoute tabLabel="Grades" />
<View
style={{ flex: 1, justifyContent: "center" }}
tabLabel="Settings"
>
</View>
</ScrollableTabView>
</Root>
);
}
}
makeRemoteRequest = () => {
//do request stuff
};
handleRefresh = () => {
this.makeRemoteRequest();
};
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: "86%",
backgroundColor: "black",
}}
/>
);
};
renderHeader = () => {
return <View />;
};
classSelected = className => {
//do stuff
};
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View>
<ActivityIndicator animating size="large" />
</View>
);
};
const HomeRoute = () => (
<List containerStyle={{ borderTopWidth: 0, borderBottomWidth: 0 }}>
<FlatList
style={{ width: width }}
data={this.state.data}
renderItem={({ item }) => (
<View style={{ left: "9%", padding: 6 }}>
<TouchableOpacity onPress={() => this.classSelected(item.name)}>
<Text
style={{
fontSize: 16
}}
>
{item.name}
</Text>
<Text
style={{
fontSize: 12
}}
>
{item.grade}
</Text>
<Text
style={{
fontSize: 12
}}
>
{item.letterGrade}
</Text>
</TouchableOpacity>
</View>
)}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
ListFooterComponent={this.renderFooter}
keyExtractor={item => item.name}
/>
</List>
);
The error I get is 'TypeError: Cannot read property 'data' of undefined' within HomeRoute. I think the error is in this line: data={this.state.data}.
I am defining data correctly? Am I even correctly setting up the FlatList? Or does it have to do with how I am passing down application state?
If you need any other code to be appended to the question, you can just ask in the comments.
Thanks in advance
You've declared the state in is parent component, causing this.state is undefined in its child component.
When you use the HomeRoute component, you need to pass the state data from its parent component.
render() {
return (
<Root>
<ScrollableTabView initialPage={0} tabBarPosition="top">
<HomeRoute tabLabel="Grades" data={this.state.data} />
<View
style={{ flex: 1, justifyContent: "center" }}
tabLabel="Settings"
>
</View>
</ScrollableTabView>
</Root>
);
}
and in the HomeRoute itself, you need to extract data from its props.
const HomeRoute = ({data}) => (
<List containerStyle={{ borderTopWidth: 0, borderBottomWidth: 0 }}>
<FlatList
style={{ width: width }}
data={data}
renderItem={({ item }) => (
<View style={{ left: "9%", padding: 6 }}>
<TouchableOpacity onPress={() => this.classSelected(item.name)}>
<Text
style={{
fontSize: 16
}}
>
{item.name}
</Text>
<Text
style={{
fontSize: 12
}}
>
{item.grade}
</Text>
<Text
style={{
fontSize: 12
}}
>
{item.letterGrade}
</Text>
</TouchableOpacity>
</View>
)}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
ListFooterComponent={this.renderFooter}
keyExtractor={item => item.name}
/>
</List>
);
Several functions, including HomeRoute, are not defined within the MyAppsName class. Therefore, this in these functions doesn't point to the correct this. I suggest to put them inside the class and bind all the functions that use this.
You get a syntax error because they are not defined properly. Follow the pattern of the definition of render, for example:
makeRemoteRequest() {
Instead of
makeRemoteRequest = () => {