How to show ActivityIndictor when data is fetched in react native - reactjs

I have a react native app with PHP backEnd (SQL server DB)
Well ,As you see in pictures ,I have a form where user can enter month and year and search DB's information ;
My code do:
1/ if a variable is setting true => I will get just my form
2/ if I click on button => variable became false and show the form and data ;
My problem is when I click on button ,it takes some time to show results so in this case I wan add an ActivityIndicator as a sign that something is working behind ;
This is my code :
export default class FirstPage extends React.Component {
constructor(props){
super(props);
this.state ={
isLoading: true,
dataSource: [],
month:'',
year:'',
}
}
afficher = () =>{
this.setState({
Loading: false})
const month = this.state.month;
const year= this.state.year;
return fetch('http://192.168.1.2:80/netOne/fetch.php',{
method:'post',
header:{
'Accept':'application/json',
'Content-type' :'application/json'
},
body:JSON.stringify({mois:month,annee:year})})
.then((response) => response.json())
.then((responseJson) => {
if(responseJson=="null"){
}
else {this.setState({
isLoading: false,
dataSource: responseJson,});}}
)
.catch((error) =>{console.error(error);});
this.setState({
month:'',
year:'',})
}
render() {
if(this.state.isLoading){
return(
<View style={{flex: 1}}>
<View style={{alignItems: 'center' }}>
<View style={{marginTop:30,width:Dimensions.get("window").width*0.8,backgroundColor:'#ffffff',height:150}}>
<Text style={{marginTop:20,marginLeft:20,color:'grey'}}> Month :</Text>
<TextInput placeholder="Enter value" style={{marginLeft:20,paddingLeft:5,marginRight:20,borderBottomColor: '#f2f2f2',borderBottomWidth: 1,}} onChangeText= {month=>this.setState({month})}/>
<Text style={{marginTop:20,marginLeft:20,color:'grey'}}> Year :</Text>
<TextInput placeholder="Enter value" style={{marginLeft:20,marginRight:20,paddingLeft:5,borderBottomColor: '#f2f2f2',borderBottomWidth: 1,}} onChangeText= {year=>this.setState({year})}/>
</View>
<TouchableOpacity style={{borderRadius:12,width:Dimensions.get("window").width*0.8,backgroundColor:'#ff9900',height:50,marginTop:10}} onPress={this.afficher}>
<Text style={{marginTop:15,color:'white',textAlign:'center',fontSize:14}}>Afficher</Text>
</TouchableOpacity>
</View>
</View>
)}
return (
<ScrollView style={{ flex: 1,backgroundColor:'#f2f2f2'}}>
<View style={{alignItems: 'center' }}>
<View style={{marginTop:30,width:Dimensions.get("window").width*0.8,backgroundColor:'#ffffff',height:150}}>
<Text style={{marginTop:20,marginLeft:20,color:'grey'}}> Month :</Text>
<TextInput placeholder="Enter value" style={{marginLeft:20,paddingLeft:5,marginRight:20,borderBottomColor: '#f2f2f2',borderBottomWidth: 1,}} onChangeText= {month=>this.setState({month})}/>
<Text style={{marginTop:20,marginLeft:20,color:'grey'}}> Year :</Text>
<TextInput placeholder="Enter value" style={{marginLeft:20,marginRight:20,paddingLeft:5,borderBottomColor: '#f2f2f2',borderBottomWidth: 1,}} onChangeText= {year=>this.setState({year})}/>
</View>
<TouchableOpacity style={{borderRadius:12,width:Dimensions.get("window").width*0.8,backgroundColor:'#ff9900',height:50,marginTop:10}} onPress={this.afficher}>
<Text style={{marginTop:15,color:'white',textAlign:'center',fontSize:14}}>Afficher</Text>
</TouchableOpacity>
</View>
<View style={{ paddingLeft:10 ,paddingTop:10 ,paddingBottom:10}}>
<View style={{ flexDirection:'row' }}>
<Text style={styles.head}> Client </Text>
<Text style={styles.head1}>Mois</Text>
<Text style={styles.head2}>Annee</Text>
<Text style={styles.head3}>ChiffreAffaire</Text>
</View>
<FlatList
data={this.state.dataSource}
renderItem={({item}) =><Item title={item.M500_NOM} title1={item.Mois} title2={item.Annee} title3={item.ChiffreAffaire}/>}
ListEmptyComponent={this._listEmptyComponent}
keyExtractor={(item, index) => index.toString()}
/>
</View>
</ScrollView>
);
}
}

Here is an updated version of your code.
return (
<ScrollView style={{ flex: 1,backgroundColor:'#f2f2f2'}}>
<View style={{alignItems: 'center' }}>
<View style={{marginTop:30,width:Dimensions.get("window").width*0.8,backgroundColor:'#ffffff',height:150}}>
<Text style={{marginTop:20,marginLeft:20,color:'grey'}}> Month :</Text>
<TextInput placeholder="Enter value" style={{marginLeft:20,paddingLeft:5,marginRight:20,borderBottomColor: '#f2f2f2',borderBottomWidth: 1,}} onChangeText= {month=>this.setState({month})}/>
<Text style={{marginTop:20,marginLeft:20,color:'grey'}}> Year :</Text>
<TextInput placeholder="Enter value" style={{marginLeft:20,marginRight:20,paddingLeft:5,borderBottomColor: '#f2f2f2',borderBottomWidth: 1,}} onChangeText= {year=>this.setState({year})}/>
</View>
<TouchableOpacity style={{borderRadius:12,width:Dimensions.get("window").width*0.8,backgroundColor:'#ff9900',height:50,marginTop:10}} onPress={this.afficher}>
<Text style={{marginTop:15,color:'white',textAlign:'center',fontSize:14}}>Afficher</Text>
</TouchableOpacity>
{(this.state.dataSource.length != 0) </View>
<View style={{ paddingLeft:10 ,paddingTop:10 ,paddingBottom:10}}>
<View style={{ flexDirection:'row' }}>
<Text style={styles.head}> Client </Text>
<Text style={styles.head1}>Mois</Text>
<Text style={styles.head2}>Annee</Text>
<Text style={styles.head3}>ChiffreAffaire</Text>
</View>
<FlatList
data={this.state.dataSource}
renderItem={({item}) =><Item title={item.M500_NOM} title1={item.Mois} title2={item.Annee} title3={item.ChiffreAffaire}/>}
ListEmptyComponent={this._listEmptyComponent}
keyExtractor={(item, index) => index.toString()}
/>
</View>}
{this.state.loading &&
<ActivityIndicator/>
}
</ScrollView>
);

Related

React Native - ScrollView not scrolling

I'm currently making a registration form using React Native. When I implement into the application, a scroll bar doesn't work.
return (
<TouchableWithoutFeedback
onPress={() => {
Keyboard.dismiss();
}}>
<View style={styles.container}>
<ScrollView>
<View style={styles.formContainer}>
<View style={styles.registerTextContainer}>
{/* <Text style={styles.registerText}>Register for an account</Text> */}
</View>
<Form type={User} ref={c => (this._form = c)} options={options} />
<TouchableOpacity
style={styles.registerButtonContainer}
onPress={this.handleSubmit}>
<Text style={styles.registerButtonText}>REGISTER</Text>
</TouchableOpacity>
</View>
</ScrollView>
</View>
</TouchableWithoutFeedback>
);
}
This is how the application currently looks
Trying wrapping the whole page with ScrollView instead of TouchableWithoutFeedback and set flex to 1
return (
<ScrollView style={{ flex: 1 }}>
<TouchableWithoutFeedback
onPress={() => {
Keyboard.dismiss();
}}
>
<View style={styles.container}>
<View style={styles.formContainer}>
<View style={styles.registerTextContainer}>
{/* <Text style={styles.registerText}>Register for an account</Text> */}
</View>
<Form type={User} ref={(c) => (this._form = c)} options={options} />
<TouchableOpacity
style={styles.registerButtonContainer}
onPress={this.handleSubmit}
>
<Text style={styles.registerButtonText}>REGISTER</Text>
</TouchableOpacity>
</View>
</View>
</TouchableWithoutFeedback>
</ScrollView>
);
Don't set flex:1 in scroll view, instead try
<ScrollView contentContainerStyle={{ flexGrow: 1}}>

changing the styling of one text element from inside another text element

so basically, am trying to achieve something like so, such that when +100 is pressed, the color of say, Upload ID Card changes to really show that that field is completed.
<View
style={{ justifyContent: "flex-start", marginTop: 25 }}
>
<Text
style={ styles.scoreTitle }
>
{item.key}
</Text>
</View>
<View style={styles.perScoreRightContentView}>
<Text
style={styles.scorePlus100}
onPress={() => // change style of the the text child above}
>
+ 100
</Text>
<MaterialIcons name="keyboard-arrow-right" size={24} />
</View>
</View>
So, this is what I have tried out but with no success;
...
const [isSelected, setIsSelected] = React.useState(false);
...
<Text
style={[
isSelected
? { ...styles.scoreTitle, color: "#C6C6C6" }
: styles.scoreTitle
]}
>
{item.key}
</Text>
</View>
<TouchableOpacity
style={styles.perScoreRightContentView}
onPress={() => setIsSelected(!isSelected)}
>
<Text style={styles.scorePlus100}>+ 100</Text>
<MaterialIcons name="keyboard-arrow-right" size={24} />
</TouchableOpacity>
...
const styles = StyleSheet.create({
scoreTitle: {
color: style.color.blackText,
fontSize: 13,
fontFamily: style.fontFamily.medium
}
});
Now I understand, you can put a ref on the text element and access to syle of that text element from the press function.
some thing like that :
<View style={{ justifyContent: "flex-start", marginTop: 25 }}>
<Text style={ styles.scoreTitle } ref='colorText'>
{item.key}
</Text>
</View>
<View style={styles.perScoreRightContentView}>
<Text style={styles.scorePlus100} onPress={() => changeStyle()}>
+ 100
</Text>
<MaterialIcons name="keyboard-arrow-right" size={24} />
</View>
const changeStyle = () => {
const myReference = this.colorText.current // The DOM element
myReference.style.color = "yellow";
}
don't forget to useRef to declar the ref.
I actually found a solution, thanks rovas
So basically what had to be done was to split components such that they manage different state, that is to say,
const Score = ({ title }: { title: string }) => {
const [scoreSelected, setScoreSelected] = React.useState(false);
return (
<View style={styles.perSectionScore}>
<View style={{ justifyContent: "flex-start", marginTop: 25 }}>
<Text
style={[
scoreSelected
? { ...styles.scoreTitle, color: "#C6C6C6" }
: styles.scoreTitle
]}
>
{title}
</Text>
</View>
<View
style={styles.perScoreRightContentView}
>
<Text
style={styles.scorePlus100}
onPress={() => {
setScoreSelected(!scoreSelected);
}}
>
+ 100
</Text>
<MaterialIcons name="keyboard-arrow-right" size={24} />
</View>
</View>
);
};
and then use in a to-be rendered component, i.e
<View style={styles.scoresContainer}>
<FlatList
data={scoreTitles}
renderItem={({ item }) => {
const index = scoreTitles.indexOf(item);
return (
<>
{
<View
key={index}
style={{
padding: 10
}}
>
<Score title={item.key}/>
<View style={{ flex: 0.5 }}>
<Input
disabled={true}
inputContainerStyle={{ borderBottomColor: "#EAEAEA" }}
/>
</View>
</View>
}
</>
);
}}
/>
</View>
</View>
);
...

Error in FlatList :Tried to get a frame for out of range index NaN

In my react native application ,I have a form where I enter specific month and year to show some informations from my SQL data using PHP,
The problem is when I enter month or year that doesn't exist ,It gives me the error:Tried to get a frame for out of range index NaN
I add the flatList property : List empty but It doesn't work as I expect !! (In one second ,the message of having empty list shows then the error msg in red and this because I'm rendering empty child I think)
This is my code :
function Item({ title,title1,title2,title3 }) {
return (
<View style={styles.item}>
<Text style={styles.title}>{title}</Text>
<Text style={styles.title1}>{title1}</Text>
<Text style={styles.title2}>{title2}</Text>
<Text style={styles.title3}>{title3}</Text>
</View>
);
}
export default class FetchExample extends React.Component {
constructor(props){
super(props);
this.state ={ isLoading: true,
dataSource: [],
month:'',
year:'',
}
}
userRegister = () =>{
const month = this.state.month;
const year= this.state.year;
return fetch('http://192......',{
method:'post',
header:{
'Accept':'application/json',
'Content-type' :'application/json'
},
body:JSON.stringify({mois:month,annee:year})})
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
dataSource: responseJson,});})
.catch((error) =>{console.error(error);});
this.setState({
month:'',
year:'',})
}
_listEmptyComponent = () => {
return (
<View>
<Text>Votre choix n'existe pas </Text>
</View>
)
}
render(){
return(
<View style={{flex: 1}}>
<View style={{backgroundColor:'#58ACFA',flex:1,justifyContent: 'center'}}>
<TouchableOpacity style={{marginTop:32,marginLeft:20}} onPress={this.props.navigation.openDrawer }>
<FontAwesome5 name="bars" size={24} color="#161924" />
</TouchableOpacity >
</View>
<View style={{flex:1 ,flexDirection:'row' }}>
<View style={styles.pass}>
<TextInput placeholder='year ' style={{flex:1,paddingLeft:5}} onChangeText= {year=>this.setState({year})}/></View>
<View style={styles.pass}>
<TextInput placeholder='Month ' style={{flex:1,paddingLeft:5}} onChangeText= {month=>this.setState({month})}/></View>
<View style={styles.pass}>
<TouchableOpacity style={styles.butt} onPress={this.userRegister}>
<Text style={{marginTop:8,color:'grey'}}>Afficher</Text>
</TouchableOpacity></View>
</View>
<View style={{flex:7 ,paddingLeft:10 ,paddingTop:10 ,paddingBottom:10}}>
<View style={{ flexDirection:'row' }}>
<Text style={styles.head}> Client </Text>
<Text style={styles.head1}>Mois</Text>
<Text style={styles.head2}>Annee</Text>
<Text style={styles.head3}>ChiffreAffaire</Text>
</View>
<FlatList
data={this.state.dataSource}
renderItem={({item}) =><Item title={item.M500_NOM} title1={item.Mois} title2={item.Annee} title3={item.ChiffreAffaire}/>}
ListEmptyComponent={this._listEmptyComponent}
keyExtractor={(item, index) => index.toString()}
/>
</View>
</View>
);
}
}

Cannot access the state but i see it on debbugger

I have function to fetch my data, and i do setState to put my data inside my state.
But i dont understand how to use it in my render()
getFixture = async () => {
const url = 'http://127.0.0.1:80/testmatch/get_fixture.php';
fetch(url).then((reponse) => reponse.json())
.then((reponseJson) => {
this.setState({
data:reponseJson,
isLoading:false
})
})
}
componentDidMount(){
this.getFixture()
}
if i do a console.log(this.state.data); in my render is show me this in the console (in image join)
if i do console.log(this.state.data.elapsed); is working and i get the value but if i do console.log(this.state.data.awayTeam.logo); i get Cannot read property 'logo'
I dont understand why.
Screenshot
Here is all the code, that i want is to use all datas from my data State to my render :
getFixture = async () => {
const url = 'http://127.0.0.1:80/testmatch/get_fixture.php';
fetch(url).then((reponse) => reponse.json())
.then((reponseJson) => {
this.setState({
data:reponseJson,
isLoading:false
})
console.log(this.state.data.awayTeam.logo); // WORKING (SHOW ME THE LINK)
})
}
render() {
console.log(this.state.data.awayTeam.logo); // NOT WORKING (CANNOT READ PROPERTY OF UNDEFINED)
return (
<View style={styles.container}>
<View style={styles.containerScore}>
<View style={{flex: 1, flexDirection: 'row', borderColor:'#171F33',borderBottomWidth: 1 }}>
<View style={{flex: 1,paddingTop:7,paddingBottom:7}}>
<View style={{flex: 1}}>
<Image style={{width: 50, height: 50}} source={{uri: "toto"}} />
</View>
</View>
<View style={{flex: 1,paddingTop:7,paddingBottom:7, backgroundColor:'#fff'}}>
<Text style={{fontSize:13}}> {this.state.data.elapsed}</Text>
</View>
<View style={{flex: 1,paddingTop:7,paddingBottom:7, marginLeft:2, backgroundColor:'#000'}}>
<Text style={{fontSize:13}}></Text>
</View>
</View>
<Text style={{color:"#FFF"}}>{} </Text>
</View>
<View style={styles.containerInfo}>
<ScrollableTabView style={{marginTop: 1}} initialPage={0} renderTabBar={() => <CustomTabBar/>} >
<View tabLabel='Tab #1'>
<Text>My</Text>
</View>
<View tabLabel='Tab #2'>
<Text>favorite</Text>
</View>
<View tabLabel='Tab #3'>
<Text>favorite</Text>
</View>
<View tabLabel='Tab #4'>
<Text>favorite</Text>
</View>
</ScrollableTabView>
</View>
</View>
);
}
}
In the initial render, the this.state.data is not yet set, so if you try to access it without null checking it will give you an error.
In your jsx, you can check if this.state.data is falsy and if it is falsy return immediately like this:
render() {
if (!this.state.data) {
return (<View><Text>Loading...</Text></View>);
}
console.log(this.state.data.awayTeam.logo);
return (
<View style={styles.container}>
<View style={styles.containerScore}>
<View style={{flex: 1, flexDirection: 'row', borderColor:'#171F33',borderBottomWidth: 1 }}>
<View style={{flex: 1,paddingTop:7,paddingBottom:7}}>
<View style={{flex: 1}}>
<Image style={{width: 50, height: 50}} source={{uri: "toto"}} />
</View>
</View>
<View style={{flex: 1,paddingTop:7,paddingBottom:7, backgroundColor:'#fff'}}>
<Text style={{fontSize:13}}> {this.state.data.elapsed}</Text>
</View>
<View style={{flex: 1,paddingTop:7,paddingBottom:7, marginLeft:2, backgroundColor:'#000'}}>
<Text style={{fontSize:13}}></Text>
</View>
</View>
<Text style={{color:"#FFF"}}>{} </Text>
</View>
<View style={styles.containerInfo}>
<ScrollableTabView style={{marginTop: 1}} initialPage={0} renderTabBar={() => <CustomTabBar/>} >
<View tabLabel='Tab #1'>
<Text>My</Text>
</View>
<View tabLabel='Tab #2'>
<Text>favorite</Text>
</View>
<View tabLabel='Tab #3'>
<Text>favorite</Text>
</View>
<View tabLabel='Tab #4'>
<Text>favorite</Text>
</View>
</ScrollableTabView>
</View>
</View>
)
}
A simple demo in codesandbox
Try to log in the setState callback like this
this.setState({
data:reponseJson,
isLoading:false
}, () => {
console.log(this.state.data.awayTeam.logo)
})

flatlist showing type error : null is not a key

I am getting this error while trying to fetch data from React Native. Earlier it was working fine but now it is not working and I can't find out why.
<FlatList
data={this.state.favArr}
renderItem={({ item }) => (
<TouchableOpacity
style={styles.itemContainer}
onPress={() => this.handleTap({ item })}
>
<Image
resizeMode="cover"
style={styles.contentImage}
source={{
uri: "https://images.pexels.com/photos/186077/pexels-photo-186077.jpeg?auto=compress&cs=tinysrgb&h=350"
}}
/>
<TouchableOpacity
onPress={() => this.unFavButtonTapped({ item })}
style={styles.unFavBtnStyle}
>
<Image
style={{
height: 25,
width: 25,
alignSelf: "center"
}}
source={require("../Assets/ic_fill_heart.png")}
/>
</TouchableOpacity>
<View style={styles.apartment}>
<Text style={fontLoaded ? styles.itemLocationFont : styles.item}>
{item.bedroom} BHK Apartment{" "}
</Text>
<Text
style={fontLoaded ? styles.LocationitemAveniur : styles.Locationitem}
>
{item.area}, {item.city}
</Text>
<Text style={fontLoaded ? styles.feetitemAveniur : styles.feetitem}>
{item.builtUpArea} ft.{" "}
</Text>
<Text style={fontLoaded ? styles.itemLocationFont : styles.item}>
₹{item.price}{" "}
</Text>
<Text style={fontLoaded ? styles.RightItemAveniur : styles.Rightitem}>
Posted On {item.uploadDate}
</Text>
<Text style={fontLoaded ? styles.expiryItemAveniur : styles.expiryItem}>
Expires On {item.expiryDate}
</Text>
{
<TouchableOpacity onPress={() => this.handleUnfavourite({ item })}>
<Text style={styles.UnFavitem}>UnFavourite</Text>
</TouchableOpacity>
}
</View>
</TouchableOpacity>
)}
keyExtractor={item => item.key}
numColumns={numColumns}
/>
replace this line:
keyExtractor={item => item.key}
with:
keyExtractor={(item, index) => index.toString()}

Resources