i have two components one is called homeScreen the second is card i do fetch data in homeScreen i set it to state after i do send state through props to my card component .
Now my card components should generate 9 cards accoridng to the data i am sending through to it so i did map and i am getting this error
TypeError: Cannot read property '0' of undefined.
i tried to console.log props inside Card component and i could see data but for some reason the map isnt working
Card.js
const Card = props => {
Array.from({length: 9}).map((i, index) => {
console.log(props);
return (
<View style={{flex: 1}}>
<Text style={{flex: 1, backgroundColor: 'red'}}>
{props.title[1] ? `${props.title[index]}` : 'Loading'}
</Text>
<Text style={{flex: 1, backgroundColor: 'blue'}}>{props.rating[index]}</Text>
</View>
);
});
};
export default Card;
homeScreen.js
export default class HomeScreen extends React.Component {
state = {
title: [],
image: [],
rating: [],
isLoading: true,
};
componentDidMount() {
this.getData();
}
titleSend = () => {
if (!this.state.isLoading) {
{
Array.from({length: 9}).map((i, index) => {
return this.state.title[index];
});
}
}
};
imageSetter = () => {
Array.from({length: 9}).map((i, keys) => {
return (
<Image
key={keys}
style={{width: 50, height: 50, flex: 1}}
source={{uri: this.state.image[keys]}}
/>
);
});
};
getData = () => {
const requestUrls = Array.from({length: 9}).map(
(_, idx) => `http://api.tvmaze.com/shows/${idx + 1}`,
);
const handleResponse = data => {
const shows = data.map(show => show.data);
this.setState({
isLoading: false,
title: shows.map(show => show.name),
image: shows.map(show => show.image.medium),
rating: shows.map(show => show.rating.average),
});
// console.log(this.state);
};
const handleError = error => {
this.setState({
isLoading: false,
});
};
Promise.all(requestUrls.map(url => axios.get(url)))
.then(handleResponse)
.catch(handleError);
};
render() {
const {isLoading, title, image, rating} = this.state;
if (isLoading) {
return <ActivityIndicator size="large" color="#0000ff" />;
}
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<ScrollView style={{flex: 1, backgroundColor: 'red'}}>
<Card title={this.state.title} />
</ScrollView>
<Text>here images</Text>
</View>
);
}
}
None of your functions/methods using Array.from are returning a value.
For example your Card component:
const Card = props => {
// note addition of `return` statement
return Array.from({length: 9}).map((i, index) => {
console.log(props);
return (
<View style={{flex: 1}}>
<Text style={{flex: 1, backgroundColor: 'red'}}>
{props.title[1] ? `${props.title[index]}` : 'Loading'}
</Text>
<Text style={{flex: 1, backgroundColor: 'blue'}}>{props.rating[index]}</Text>
</View>
);
});
};
export default Card;
The titleSend and imageSetter methods have a similar issue.
The index error is because you're not passing an rating prop to the Card component but you're accessing props.rating[0], props.rating[1], etc.
return (
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}}>
<ScrollView style={{flex: 1, backgroundColor: 'red'}}>
// missing `rating` prop
<Card title={this.state.title} />
</ScrollView>
<Text>here images</Text>
</View>
);
Related
I am trying to display some fetched products in a FlatList, also to display more products when I reach the end of this FlatList, but I am getting this error: Invariant Violation: ScrollView child layout (["alignItems"]) must be applied through the contentContainerStyle prop.
When I change alignItems from style to contentContainerStyle the app closes without showing an error or alert.
If I remove the alignItems from container the app closes too
export default function NewProducts() {
const [products, setProducts] = useState([]);
const [isLoading, setisLoading] = useState(false);
const [startLimit, setStartLimit] = useState({ start: 0, limit: 10 });
const navigation = useNavigation();
useEffect(() => {
setisLoading(true);
getProducts();
}, [startLimit]);
const gotoProduct = (id) => {
navigation.push("product", { idProduct: id });
};
const getProducts = async () => {
const response = await getLastProductsApi(
startLimit.start,
startLimit.limit
);
console.log(response);
setProducts(response);
};
const renderItem = ({product}) => {
return (
<TouchableWithoutFeedback
key={product.id}
onPress={() => gotoProduct(product.id)}
>
<View style={styles.containerProduct}>
<View style={styles.product}>
<Image
style={styles.image}
source={{
uri: `${product.attributes.images.data[0].attributes.formats.small.url}`,
}}
/>
<Text style={styles.name} numberOfLines={1} ellipsizeMode="tail">
{product.attributes.title}
</Text>
</View>
</View>
</TouchableWithoutFeedback>
);
};
const renderFooter = () => {
return isLoading && <Loading text="Loading more products" size="medium" />;
};
const handleLoadMore = () => {
setStartLimit({
start: startLimit.start + 10,
limit: startLimit.limit + 10,
});
setisLoading(true);
};
return (
<FlatList
style={styles.container}
numColumns={2}
data={products}
renderItem={renderItem}
keyExtractor={(item, index) => index.toString()}
ListFooterComponent={renderFooter}
onEndReached={handleLoadMore}
onEndReachedThreshold={0}
/>
);
}
const styles = StyleSheet.create({
container: {
alignItems: "flex-start",
marginTop: 1,
},
containerProduct: {
padding: 3,
},
product: {
padding: 10,
backgroundColor: "#f0f0f0",
borderRadius: 20,
},
image: {
height: 150,
resizeMode: "contain",
borderRadius: 20,
},
name: {
marginTop: 15,
fontSize: 15,
},
});
Here is where I call this component
export default function Home() {
return (
<>
<StatusBarCustom
backgroundColor={colors.primary}
barStyle="light-content"
/>
<Search />
<View>
<Banner />
<NewProducts />
</View>
</>
);
}
When you use renderItem from FlatList you have to use item and not product: https://reactnative.dev/docs/flatlist#required-renderitem
You can replace
const renderItem = ({product}) => {
By
const renderItem = ({item}) => {
I'm new to React native and development in general and am trying to retrieve data from an webservice and then render it but I seem to be running into different errors.
I am getting this error
import React, { Component } from "react";
import {StyleSheet,View,ActivityIndicator,FlatList,Text,TouchableOpacity} from "react-native";
export default class Source extends React.Component {
static navigationOptions = ({ navigation }) => {
return {
title: "Source Listing",
headerStyle: {backgroundColor: "#fff"},
headerTitleStyle: {textAlign: "center",flex: 1}
};
};
constructor(props) {
super(props);
this.state = {
loading: false,
items:[]
};
this.fetchRequest=this.fetchRequest.bind.this
}
FlatListItemSeparator = () => {
return (
<View style={{
height: .5,
width:"100%",
backgroundColor:"rgba(0,0,0,0.5)",
}}
/>
);
}
componentDidMount()
{
fetchRequest();
}
renderItem=(data)=>
<TouchableOpacity style={styles.list}>
<Text style={styles.lightText}>{data.item.name}</Text>
<Text style={styles.lightText}>{data.item.email}</Text>
<Text style={styles.lightText}>{data.item.company.name}</Text>
</TouchableOpacity>
render(){
fetchRequest()
{
const parseString = require('react-native-xml2js').parseString;
fetch('http://192.168.200.133/apptak_service/apptak.asmx/Get_Item_Master')
.then(response => response.text())
.then((response) => {
parseString(response, function (err, result) {
console.log(response)
});
}).catch((err) => {
console.log('fetch', err)
this.fetchdata();
})
if(this.state.loading){
return(
<View style={styles.loader}>
<ActivityIndicator size="large" color="#0c9"/>
</View>
)}}
return(
<View style={styles.container}>
<FlatList
data= {this.state.dataSource}
ItemSeparatorComponent = {this.FlatListItemSeparator}
renderItem= {item=> this.renderItem(item)}
keyExtractor= {item=>item.id.toString()}
/>
</View>
)}
}
<FlatList
data={this.state.items}
renderItem={({ item }) => <Item title={item.title} />}
keyExtractor= {item=>item.id.toString()}
/>
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff"
},
loader:{
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#fff"
},
list:{
paddingVertical: 4,
margin: 5,
backgroundColor: "#fff"
}
});
The main cause what i am trying to achieve is render the 'items' that are returned from the webservice.
Kindly guide me with this error
I am creating a ContactListScreen. The immediate child of ContactListScreen is ContactItems and ContactItems is a sectionList which renders each ContactItem.
But the problem arises, as my ContactItems should be multi-selectable.
I passed the array of selectedContacts from my state to every ContactItem. The logic here I used is ContactItem checks if the length of selectedContacts is 0 or not. If the length is zero it should not render any selectItemView, if I select an item, it should push itself to the selectedContacts using a callback. But the problem is the children components (ContactItem)s doesn't get updated until I selected deselect an item twice or thrice. How can I make it work?
Part of ContactList.tsx
class ContactList extends Component {
this.state = {
loading: false,
error: null,
data: [],
selectedItems: []
};
handleSelectionPress = (item) => {
this.setState(prevState => {
const { selectedItems } = prevState;
const isSelected = selectedItems.includes(item);
return {
selectedItems: isSelected
? selectedItems.filter(title => title !== item)
: [item, ...selectedItems],
};
});
};
renderItem(item: any) {
return <ContactItem item={item.item}
isSelected={this.state.selectedItems.includes(item.item)}
onPress={this.handleSelectionPress}
selectedItems={this.state.selectedItems}
/>;
}
render() {
return (
<View style={styles.container}>
<SectionList
sections={this.state.data}
keyExtractor={(item, index) => item.id}
renderItem={this.renderItem.bind(this)}
renderSectionHeader={({section}) => (
section.data.length > 0 ?
<Text>
{section.title}
</Text> : (null)
)}
/>
</View>
);
}
}
Part of ContactItem.tsx
class ContactItem extend Component {
render() {
const checkBox = <TouchableOpacity onPress={() => {
this.props.onPress(this.props.item)
}
} style={this.props.selectedItems.length > 0 && {display: 'none'}}>
{!this.props.isSelected ?
<View style={{borderRadius: 10, height: 20, width: 20, borderColor: "#f0f", borderWidth: 1}}>
</View> : <View style={{
borderRadius: 10,
height: 20,
width: 20,
borderColor: "#f0f",
borderWidth: 1,
backgroundColor: "#f0f"
}}>
</View>}
</TouchableOpacity>
return (
<View style={this.styles.contactsContainer}>
<TouchableOpacity
onLongPress={() => this.props.onPress(this.props.item)}>
<View style={this.styles.contactInfo}>
{checkBox}
</View>
</TouchableOpacity>
</View>
);
}
Note: Functional Components are not used where I work.
I'm not 100% certain about this, but I have a feeling that the problem is that the SectionList component isn't triggering its update because the supplied sections={this.state.data} property never changes.
The easiest way to handle this is to add the selectedItems as an extraData property to section list:
<SectionList
sections={this.state.data}
extraData={this.state.selectedItems}
//...
At my example, the function “getData” loading my data, but after the loading, I try to print and show the total sum of the objects that came from JSON in a footer at the bottom of the screen.
and I don't really know how to do it.
I don't understand how to solve this issue coz I have tried many ways.
This is my example:
export default class MainScreen extends Component {
constructor(props) {
super(props);
this.state = { data: [] };
}
getData = () => {
this.setState({ isLoading: true })
axios.get("https://rallycoding.herokuapp.com/api/music_albums")
.then(res => {
this.setState({
isLoading: false,
data: res.data
});
console.log(res.data);
});
}
componentDidMount() {
this.props.navigation.setParams({getData: this.getData}); //Here I set the function to parameter
this.getData()
}
renderItem(item) {
const { title, artist} = item.item;
return (
<TouchableOpacity
onPress={() => this.props.navigation.navigate("Settings")}
>
<Card
containerStyle={{
borderColor: "black",
padding: 20,
height: 100,
backgroundColor: "#e6e6ff",
borderBottomEndRadius: 10,
borderTopRightRadius: 10,
borderBottomStartRadius: 10,
}}
>
<View
style={{
paddingVertical: 15,
paddingHorizontal: 10,
flexDirection: "row",
justifyContent: "space-between",
alignItems: "center"
}}
>
<Icon name="chevron-right" size={30} color={"grey"} justifyContent={"space-between"} />
<Text style={styles.name}>
{title+ " " + artist}
</Text>
{/* <Text style={styles.vertical} numberOfLines={2}></Text> */}
</View>
</Card>
</TouchableOpacity>
);
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, paddingTop: 230 }}>
<Text
style={{ alignSelf: "center", fontWeight: "bold", fontSize: 20 }}
>
loading data...
</Text>
<ActivityIndicator size={'large'} color={'#08cbfc'} />
</View>
);
}
return (
<View style={styles.container}>
<FlatList
data={this.state.data}
renderItem={this.renderItem.bind(this)}
keyExtractor={item => item.id}
/>
</View>
);
}
}
/////////////////////////////////////////////////////////
MainScreen.navigationOptions = navData => {
return {
headerTitle: 'melon',
headerRight: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title=**"sync button"**
iconName={Platform.OS === "android" ? "md-sync" : "ios-sync"}
onPress={() => {
navData.navigation.navigate("getData");// here i trying to use the function
console.log("MT DATA====", navData.navigation.getParam(this.getData))//NO DATA
}}
/>
</HeaderButtons>
)
};
};
hope could you help in this situation coz its really confused me this key prop
If you are sure that all elements are unique, you can just use this key extractor in FlatList -
keyExtractor={(_, index) => String(index)}
this will ensure the uniqueness of all items in your flatlist
Probably you should set navigation param like
getData = () => {
this.setState({ isLoading: true })
axios.get("https://rallycoding.herokuapp.com/api/music_albums")
.then(res => {
this.setState({
isLoading: false,
data: res.data
});
this.props.navigation.setParams({data: res.data});
console.log(res.data);
});
}
and then in
headerRight: (
<HeaderButtons HeaderButtonComponent={HeaderButton}>
<Item
title=**"sync button"**
iconName={Platform.OS === "android" ? "md-sync" : "ios-sync"}
onPress={() => {
const data = navData.navigation.getParam("data");
console.log("MT DATA====", data);
}}
/>
</HeaderButtons>
)
I need your help I'm using firebase for my app. I'm trying to get the users ID not the logged users no all users I have. I want to show their (uid) simply like in an alert for each user. Also, I'm showing them in a flatlist and when I set item.uid in an alert it shows (undefined). But, all the other data of the user is shown correctly. This what I did until now:
**
users.js
**
export default class usersList extends React.Component{
state = {
loading: false,
uid: '',
users: [],
items: []
};
componentDidMount() {
let itemsRef = f.database().ref('users').once('value').then(snapshot => {
var data = snapshot.val();
var items = Object.values(data);
this.setState({items});
console.log(snapshot.val())
});
}
renderItem({item}) {
return (
<View key={index} style={{width: '100%', overflow:'hidden', marginBottom: 5, justifyContent:'space-between', borderBottomWidth:1, borderColor: 'grey'}}>
<View>
<View style={{padding:5, width:'100%', flexDirection: 'row', justifyContent: 'space-between'}}>
<Text>{item.email}</Text>
</View>
</View>
</View>
)
}
render() {
return (
<View style={styles.container}>
<ScrollView>
{
this.state.items.length > 0
? <ItemComponent items={this.state.items} navigation={this.props.navigation} />
: <Text>No stores</Text>
}
</ScrollView>
</View>
);
}
}
//ItemComponent.js
export default class ItemComponent extends Component {
static propTypes = {
items: PropTypes.array.isRequired
};
render() {
return (
<View style={styles.itemsList}>
{this.props.items.map((item, index) => {
return (
<View key={index}>
<TouchableOpacity
onPress={ () => alert(item.uid)}>
<Text style={styles.itemtext}>{item.email}</Text>
</TouchableOpacity>
</View>
)
})}
</View>
);
}
}
firebase.database().ref('user').on('value', (datasnapshot) => {
this.setState({
_id: datasnapshot.key
});`
This solution worked for me
<Text style={styles.yourStyleHere}>UID: {auth.currentUser?.uid} </Text>