AsyncStorage data not displayed in FlatList - javascript

I create an application that retrieves data from a URL (an array of objects) and display it in FlatList. I'm a beginner and therefore I don't use Redux or other for the moment. I would like to store my data in AsyncStorage and display them.
I tried this, but my data are not displayed int FlatList:
import React, {Component} from 'react';
import {ScrollView, View, FlatList, Image, ActivityIndicator, AsyncStorage} from 'react-native';
import axios from "axios";
import {ListItem} from "react-native-elements";
import {createAppContainer, createStackNavigator} from "react-navigation";
import AppConfig from "../../AppConfig";
import Keys from "../../data/Constants/Storage";
import PronosticsDetailsScreen from "../../screens/PronosticsDetailsScreen";
class MontanteTab extends Component {
state = {
errors: null,
isLoading: true,
pronostics: [],
};
async componentDidMount() {
const isConnected = true;
if (isConnected) {
await this.loadPronostics();
}
try {
this.setState({pronostics: JSON.parse(await AsyncStorage.getItem(Keys.pronosticsMontante))});
} catch (error) {
console.log(error);
}
}
loadPronostics() {
this.setState({isLoading: true, error: null});
return axios.get(AppConfig.apiUrl + 'montante').then(async response => {
await AsyncStorage.setItem(Keys.pronosticsMontante, JSON.stringify(this.state.pronostics));
this.setState({isLoading: false});
}).catch(error => {
this.setState({isLoading: false, error: error.response});
console.log(error);
});
}
render() {
if (this.state.isLoading === true) {
return (
<View style={{flex: 1, padding: 20}}>
<ActivityIndicator/>
</View>
)
}
return (
<View>
<ScrollView>
<View>
<FlatList
data={this.state.pronostics}
extraData={this.state.pronostics}
keyExtractor={(item, index) => index.toString()}
renderItem={({item}) => (
<ListItem
key={item.id}
roundAvatar
badge={{
value: item.statut,
textStyle: {color: '#fff'},
containerStyle: {marginRight: 0, backgroundColor: item.couleur}
}}
avatar={<Image
source={{uri: AppConfig.imagesPronosticsUrl + item.image}}
style={{borderRadius: 50, height: 50, width: 50}}/>}
title={item.competition}
subtitle={item.equipe_domicile + ' - ' + item.equipe_exterieur}
onPress={() => this.props.navigation.navigate('PronosticsDetails', {
item,
})}
/>
)}
/>
</View>
</ScrollView>
</View>
);
}
}
What's the problem please ?

I'm not an expert here, but...
One "odd" thing about FlatLists is that they are Pure Components so they don't always rerender when you expect. FlatList helps you out here and provides a property called extraData. You can use this to tell FlatList what to watch to know if there is an important change. So, try adding:
extraData={ this.state.pronostics }
to your FlatList.

The problem is solved.
I replaced :
await AsyncStorage.setItem(Keys.pronosticsMontante, JSON.stringify(this.state.pronostics));
by :
await AsyncStorage.setItem(Keys.pronosticsMontante, JSON.stringify(response.data));

Related

FlatList - Fetching Data From Postman Localhost url

Hi Everyone,
I'm very beginner to this platform.
Could any one help me to where i did mistake in the following code?
i'm Using SQL server for database
In App.js I have tried the below code...
import React, { Component } from 'react';
import {
StyleSheet,
View,
ActivityIndicator,
TouchableOpacity,
Text,
Dimensions,
FlatList
} from 'react-native';
export default class App extends React.Component {
//Set States
constructor(props)
{
super(props);
this.state={
isLoading: true,
dataSource: []
}
}
//Get Data From API
componentDidMount()
{
fetch('http://localhost:7483/api/StudentData/')
.then((response)=>response.json())
.then((responseJson)=>{
this.state({
isLoading: false,
dataSource: responseJson
})
})
}
_renderItem=({item,index}) => {
return(
<View>
<Text>Hello</Text>
</View>
);
}
render()
{
let {container}=styles
let {dataSource,isLoading}=this.state
//Use FlatList for Display Data
return(
<View style={container}>
<FlatList
data={dataSource}
renderItem={this._renderItem}
keyExtractor={(item,index) => index.toString()}
/>
</View>
);
}
}
const styles = StyleSheet.create({
container:{
flex:1,
justifyContent:'center',
alignItems:'center'
},
welcome:{
fontSize:20,
textAlign:'center',
margin:10
}
});
I'm getting data in postman url from SQL server
I'm getting this warning msg
Empty Emulator Screen
Console Warning msg
In the android emulator URL with localhost not working, so you must set ipv4 address instead of that.
Also change this.state -> this.setState
Add you IP address instead of localhost
1.) Run cmd
2.) type ipconfig
3.) Scroll Down to IPv4 Address. . . . . . . . . . . : 192.168.**.**
4.) Copy this IP and replace it in place of localhost
5.) Done
Get your IP like this
So Suppose if your IPv4 address is - 192.168.100.84 then
Your fetch should look like this
fetch('http://192.168.100.84:7483/api/StudentData/')
Also for setting state after fetch
You have to do like this
this.setState({ isLoading: false, dataSource: responseJson })
Instead of this
this.state({ isLoading: false, dataSource: responseJson })
In your render part write like this
return(
<View style={styles.container}>
<FlatList
data={this.state.dataSource}
renderItem={this._renderItem}
keyExtractor={(item,index) => index.toString()}
/>
</View>
);
Your App.js using Function Component
import React, { Component, useState, useEffect } from 'react';
import {
StyleSheet,
View,
ActivityIndicator,
TouchableOpacity,
Text,
Dimensions,
FlatList,
} from 'react-native';
export default function App() {
const [State, setState] = useState({
loading: true,
dataSource: [],
});
useEffect(() => {
GetData();
}, []);
const GetData = async () => {
const result = await fetch('http://192.168.43.159:7483/api/StudentData/');
const response = await result.json();
setState({
...State,
isLoading: false,
dataSource: response,
});
};
const _renderItem = ({ item, index }) => {
return (
<View>
<Text>Hello</Text>
</View>
);
};
return (
<View style={styles.container}>
<FlatList
data={State.dataSource}
renderItem={_renderItem}
keyExtractor={(item, index) => index.toString()}
/>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
backgroundColor: '#ecf0f1',
padding: 8,
},
});

RefreshControll data duplicate everytime do pull to refresh on ScrollView in React native

Description
I implement a pull request using RequestController in React Native, every time I did pull to refresh the same data keep adding on in Flat list over and over. I implemented pull request not inside the Flat list but on the ScrollView which wrapped the FlatList.
Actions
import React, { Component } from 'react';
import { View, StyleSheet, Text, Button, Modal, Dimensions, ScrollView, TextInput, TouchableOpacity, StatusBar, Image, Platform, TouchableNativeFeedback,FlatList, ImageBackground, RefreshControl } from 'react-native';
import axios from 'axios';
class HomeScreen extends Component{
state = {
refreshing: false,
}
componentDidMount(){
this.searchApi();
}
searchApi = async() => {
const response = await axios.get('http://73udkYid.ngrok.io/api/v1/products',{
headers: {
"x-auth-token":"eyJfaWQiOiI1ZdfjzZmM4YjIwYjBjZDQyMmJkNzUiLCJpYXQiOjE2MD"
}
}
);
this.setState({results: [...this.state.results, response.data]});
}
_onRefresh = () => {
this.setState({refreshing: true});
this.searchApi().then(() => {
this.setState({refreshing: false});
});
}
render(){
let finalGames = [];
this.state.results.forEach(obj => {
Object.keys(obj).forEach(key => {
finalGames.push(obj[key]);
});
});
return (
<ScrollView style={{flex: 1,backgroundColor: 'white',}}
refreshControl = {
<RefreshControl
refreshing = { this.state.refreshing }
onRefresh={this._onRefresh}
/>
}
>
<FlatList
data = { finalGames }
keyExtractor = {(item, index) => index.toString()}
renderItem = { ({item: itemData}) => {
if(itemData.empty == true){
return <View style = {[styles.item,styles.itemInvisible]}/>
}
return (
<View style = {{ flex: 1, margin: 4}}>
<View style = {styles.item}>
<TouchableOpacity
onPress = {() => {
this.setState({ viewController: this.state.viewController++ })
this.props.navigation.navigate(
"ProductDetail", {
itemDataDetail: itemData,
businessname:this.props.navigation.state.params.businessname,
viewController: this.state.viewController,
})
}}>
<View>
<ImageBackground
source={{ uri: itemData.photo }}
style={{ width:'100%',aspectRatio: 1, borderRadius: 15, borderWidth:1, borderColor:"#FAFAFA", overflow: 'hidden'}}>
</ImageBackground>
<View style = {{ margin: 5}}>
<Text style = {{color: '#2E2E2E', fontWeight:"bold"}} numberOfLines={1}>{itemData.item}</Text>
<Text style = {{color: '#2E2E2E', fontSize: 12, fontWeight:"normal", alignSelf: 'flex-start'}} numberOfLines={1}>Available now | Sold out</Text>
<Text style = {{color: 'white', fontSize: 18, fontWeight:"bold", backgroundColor:"#DE1F38", alignSelf: 'flex-start', paddingHorizontal: 10,paddingVertical:2,borderRadius: 8,overflow: 'hidden', marginTop: 5}} numberOfLines={1}>${itemData.price}</Text>
</View>
</View>
</TouchableOpacity>
</View>
</View>
</ScrollView>
);
}}/>
}
Output
Data duplicated every time new pull refresh triggered
I assume your api-call returns the whole list of products
This line concat api-response-data to the the list of products you already have in your component-state
this.setState({results: [...this.state.results, response.data]});
Try this instead...
this.setState({ results: response.data });
You should replace your data instead of concatenating. Use:
this.setState({ results: response.data });
Also, you should use FlatList 'onRefresh' prop to implement refresh functionality instead of using an extra ScrollView on the parent.
Oh I found a way. I just need to do this.
this.setState({results: [response.data]});
I was facing the same problem as you,
When I refreshed, the data was (data)+[(data)+(new_data)].
What happens here is that data is added to the array of this variable: results.
To prevent this you must first clear this variable: results.
So your code will look like this.
state = {
refreshing: false,
results : [],
}
when API runs, this array will filled results[{some_data},{some_data},{some_data},..],
While you refresh->
1st: The results will Empty,
2nd: reassign that array with newly added data from API.
_onRefresh = () => {
this.setState({results: []});
this.setState({refreshing: true});
this.searchApi().then(() => {
this.setState({refreshing: false});
});
}

React Native Flatlist ListItem called many times after initial render

Flatlist component as below
<FlatList
data={this.state.data}
keyExtractor={item => item.ID.toString()}
renderItem={this.renderItem}
onRefresh={this.onRefresh}
refreshing={this.state.refreshing}
ListFooterComponent={this.renderFooter}
/>
renderItem = ({ item }) => {
return (
<ListElement onPress={() => this.rowData(item)} item={item}/>
);
};
ListItem Component
import React from "react";
import { Image } from "react-native";
import { Left, Right, Body, Text, ListItem } from "native-base";
import { widthPercentageToDP as wp, heightPercentageToDP as hp } from "react-native-responsive-screen";
import Thumbnails from "../components/Thumbnails";
import styles from "../styles/HomeStyles";
import GlobalStyles from "../constants/GlobalStyles";
class ListElement extends React.Component {
componentDidMount(){
console.log(this.props.item.ID)
}
shouldComponentUpdate(){
return false;
}
render() {
return (
<ListItem onPress={this.props.onPress} thumbnail style={styles.listItem}>
<Left>
<Thumbnails imageURI={require("../../assets/images/female2.png")} />
</Left>
<Body style={{ borderBottomColor: "transparent", top: 2 }}>
<Text
style={{
fontFamily: GlobalStyles.primaryFont,
fontSize: hp("1.85%"),
}}
>
{this.props.item.FirstName} {this.props.item.LastName}
</Text>
<Text
note
style={{
fontFamily: GlobalStyles.primaryFont,
color: "#666666",
fontSize: hp("1.6%"),
}}
>
{this.props.item.Title}
</Text>
</Body>
<Right>
<Image
style={styles.rightArrow}
source={require("../../assets/images/arrowRight.png")}
/>
</Right>
</ListItem>
);
}
}
export default ListElement;
I tried to populate api data on the flatlist. Please refer my above code for implementation. Currently I am facing rerendering issues as mentioned below.
My listitem componentDidMount is invoking multiple times on scroll after even intial render of all listitems.
I have tried PureComponent and shouldComponentUpdate. Thanks in advance.
An Update
Please Find the entire code of Flatlist component
import React, { PureComponent } from "react";
import { View, FlatList } from "react-native";
import { ListItem } from "react-native-elements";
import FL from "../screens/FL";
import FL1 from "../screens/Fl1";
class FlatListDemo extends PureComponent {
constructor(props) {
super(props);
this.state = {
loading: false,
data: [],
error: null,
refreshing: false,
};
}
componentDidMount() {
this.makeRemoteRequest();
}
makeRemoteRequest = () => {
const url = `https://jsonplaceholder.typicode.com/posts`;
this.setState({ loading: true });
fetch(url)
.then((res) => res.json())
.then((res) => {
this.setState({
data: res,
error: res.error || null,
loading: false,
refreshing: false,
});
})
.catch((error) => {
this.setState({ error, loading: false });
});
};
renderItem = ({ item }) => {
return <ListElement onPress={() => this.rowData(item)} item={item} />;
};
render() {
if (this.state.loading === true) {
return <View></View>;
} else {
return (
<View>
<FlatList
data={this.state.data}
keyExtractor={(item) => item.ID.toString()}
renderItem={this.renderItem}
onRefresh={this.onRefresh}
refreshing={this.state.refreshing}
ListFooterComponent={this.renderFooter}
/>
</View>
);
}
}
}
export default FlatListDemo;
Try the following:
add to state a boolean value (you can name it "wasFetched").
Then change the componentDidMount like this:
componentDidMount() {
if(this.state.wasFetched === false) {
this.setState({ wasFetched: true }, () => this.makeRemoteRequest())
}
}

Why is the data from Firebase not rendering in my FlatList (React Native)?

I'm a beginner in React Native and I'm trying to display my data from Google Firebase in a FlatList. There are no errors that pop up, but nothing is shown in my list. I know that the componentDidMount() section works, as when I add a console.log inside it shows that offers has the correct objects inside. I'm not sure why it doesn't show up on the screen though...
import React, {Component} from 'react';
import {View, Text, StyleSheet, TextInput, SafeAreaView, Platform, Image, FlatList, TouchableHighlight} from "react-native";
import { List, ListItem, Divider } from 'react-native-elements';
import Icon from "react-native-vector-icons/Ionicons";
import { db } from '../config';
let offersRef = db.ref('/offers');
class Home extends Component {
state = {
offers: [],
currentUser: null
};
componentDidMount() {
let mounted = true;
if(mounted){
offersRef.on('value', snapshot => {
let data = snapshot.val();
let offers = Object.values(data);
this.setState({ offers });
});
}
return () => mounted = false;
}
pressRow()
{
console.log(item)
}
renderItem(item){
return(
<TouchableHighlight onPress={() => {this.pressRow(item)}}>
<Text>
{item.name}
</Text>
</TouchableHighlight>
)
}
render() {
const { currentUser } = this.state
return (
<SafeAreaView style={{ flex: 1 }}>
<FlatList>
data = {this.state.offers}
renderItem = {({ data }) => (
<TouchableHighlight onPress={() => {this.pressRow(data)}}>
<Text>
{data.name}
</Text>
</TouchableHighlight>
) }
</FlatList>
</SafeAreaView>
);
}
}
export default Home;
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
},
});
My code is above, it would be very much appreciated if someone is able to help! Thank you...
Hey please do the following changes in your render method:-
Replace "data" in renderItem with "item" and with in renderItem where ever accordingly.
<SafeAreaView style={{ flex: 1 }}>
<FlatList
data = {this.state.offers}
renderItem = {({item} ) => (
<TouchableHighlight onPress={() => {this.pressRow(item)}}>
<Text>
{item.name}
</Text>
</TouchableHighlight>
) }
/>
</SafeAreaView>

What's the reason for the error being thrown on init() method?

I used https://www.npmjs.com/package/react-native-dynamodb to implement DynamoDB access for my project. I used the same exact code as that website.
The only thing is, I can't see how my .init() method is giving me: Unresolved function or method init() upon hovering over it (I'm using the WebStorm IDE by the way). I believe that's the reason why my app won't run. Below is the code as well as the error I'm getting in the simulator.
Error in iOS Simulator
Here's my .js file:
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { ScrollView, Text, View, Button } from 'react-native';
import { logout } from '../redux/actions/auth';
import DropdownMenu from 'react-native-dropdown-menu';
import Icon from './Icon';
import DynamoDB from 'react-native-dynamodb';
let dynamodb = DynamoDB.init({
credentials: {
AccessKeyId: 'Some key',
SecretKey: 'Some key'
}
// region: 'us-east-1' - default, optional
// version: '20120810' - default, optional
})
dynamodb.table('user_choice').PutItem(
{
name: 'Jack Sparrow',
age: 30,
captain: true
},
{
ConditionExpression: "last_movie <> :movie",
ExpressionAttributeValues: {
":movie": {"S": "Pirates of the Caribbean: On Stranger Tides"}
}
})
.then((response) => console.log(response)) // AWS object response
.catch((error) => {
console.log(error)
})
class Secured extends Component {
render() {
var data = [["Literacy Leaders"], ["Wrestling Camp"], ["Screenplay Writing"], ["Panetarium Workshop"]];
return(
<ScrollView style={{padding: 20}}>
<Icon/>
<Text style={{fontSize: 27}}>
{`Welcome ${this.props.username}`}
</Text>
<View style={{flex: 1}}>
<DropdownMenu style={{flex: 1}}
bgColor={"purple"} //the background color of the head, default is grey
tintColor={"white"} //the text color of the head, default is white
selectItemColor={"orange"} //the text color of the selected item, default is red
data={data}
maxHeight={410} // the max height of the menu
handler={(selection, row) => alert(data[selection][row])} >
<View style={{flex: 1, alignItems: 'center', justifyContent: 'center'}} >
</View>
</DropdownMenu>
</View>
<View style={{margin: 20}}/>
<Button onPress={(e) => this.userLogout(e)} title="Logout"/>
</ScrollView>
);
}
}
const mapStateToProps = (state, ownProps) => {
return {
username: state.auth.username
};
}
const mapDispatchToProps = (dispatch) => {
return {
onLogout: () => { dispatch(logout()); }
}
}
export default connect(mapStateToProps, mapDispatchToProps)(Secured);
I checked the source code of react-native-dynamodb, seems DynamoDB is not exported as default but a named export.
Try import it like this:
import { DynamoDB } from 'react-native-dynamodb';

Categories

Resources