Printing arrays to screen in React Native - ios

I simply want to print a couple of arrays on screen in my React Native iOS app. Right now nothing is showing up on screen. console.logs after the for loop show that the arrays have the data they are supposed to have, but it is not reflected on screen. How do I render again after the fetch call has loaded? Here's my code:
'use unique'
import React, { Component } from 'react';
import {
StyleSheet,
TouchableHighlight,
Text,
View,
ListView
} from 'react-native';
import api from './apicall';
class APIRequest extends Component {
constructor() {
super();
this.state = {
users: [],
id: [],
type: []
}
}
componentWillMount() {
api.getData()
.then((res) => {
this.setState({
users: res
})
for (var i = 0; i < this.state.users.length; i++) {
this.state.id.push(this.state.users[i].id);
this.state.type.push(this.state.users[i].type);
});
}
render() {
return(
<View style={styles.container}>
<Text style={styles.buttonText}>
{this.state.id}
</Text>
</View>
);
}
}

this.state.id.push(this.state.users[i].id);
this.state.type.push(this.state.users[i].type);
That's the wrong way to set new state. You should do the following:
var idArray = [];
var typeArray = [];
for (var i = 0; i < this.state.users.length; i++) {
idArray.push(this.state.users[i].id);
typeArray.push(this.state.users[i].type);
}
this.setState({id: idArray});

Related

How to reload image url one more time if url shows error in loading

I am trying to load images from URL on flatlist using Image Component. In this component there is a property (onError?: () => void ) this property is called on an image fetching error.
When I run my app in low network some images failed to load, so what code should I write in (onError?: () => void ) so that the URL that failed to load images should load one more time in low network.
I am creating this App in React Native for iOS
I have done this :
App.js
import React, { useState } from 'react';
import Product from './product';
import {
FlatList,
SafeAreaView
} from 'react-native';
const products = [
{productImage: "https://media.istockphoto.com/photos/poverty-concept-used-red-shoes-for-children-in-a-thrift-shop-between-picture-id1303292803?s=612x612"},
{productImage: 'https://media.istockphoto.com/photos/poverty-concept-used-red-shoes-for-children-in-a-thrift-shop-between-picture-id1303292803?s=612x612'},
{productImage: "https://media.istockphoto.com/photos/poverty-concept-used-red-shoes-for-children-in-a-thrift-shop-between-picture-id1303292803?s=612x612"},
{productImage: 'https://media.istockphoto.com/photos/poverty-concept-used-red-shoes-for-children-in-a-thrift-shop-between-picture-id1303292803?s=612x612'},
]
const App = () => {
return (
<SafeAreaView>
<FlatList
numColumns={2}
data={products}
keyExtractor={(item, index) => index.toString()}
renderItem={({ item }) => (<Product product={item} />)}>
</FlatList>
</SafeAreaView>
);
};
export default App;
product.js
import React from 'react';
import { View, Image } from 'react-native';
class Product extends React.Component {
constructor(props){
super(props);
this.state = {
uri : this.props.product.productImage,
errorCount : 0
}
}
passInError(e) {
const { productImage } = this.props.product
if (this.state.errorCount < 3) {
this.setState({uri: productImage, errorCount: ++this.state.errorCount})
console.log(" Corrupt Image URL : " + productImage )
console.log(" Corrupt Image Error Reason : ", JSON.stringify(e) )
console.log (" Corrupt Image Reload Count : ", this.state.errorCount)
}
}
render() {
return (
<View>
<Image
style={{ width: 200, height: 200, borderWidth: 2, }}
source={{ uri:this.state.uri }}
onError = {e => this.passInError(e.nativeEvent) }
key = {this.state.errorCount}
/>
</View>
)
}
}
export default Product;
What code should I write in (onError?: () => void ) function to reload failed images URL ?
Try setting image url in state and update when error on loading image.
product.js
import React from 'react';
import { View } from 'react-native';
import FastImage from 'react-native-fast-image';
class Product extends React.Component {
constructor(props){
super(props);
this.state = {
uri : this.props.product.productImage,
errorCount : 0
}
}
render() {
const { productImage } = this.props.product
return (
<View>
<FastImage
style={{ width: 200, height: 200, borderWidth: 2, }}
source={{ uri:this.state.uri }}
resizeMode={FastImage.resizeMode.contain}
onError={e =>
this.state.errorCount < 3 &&
this.setState(
{uri: '', errorCount: ++this.state.errorCount},
() => this.setState({uri: productImage}),
)
}
/>
</View>
)
}
}
export default Product;
If I understand you correctly, you want to try to load the same image for a 2nd time when there is an error on the 1st try. I would try to re-render the component on Error (even better, wrap the image component with a wrapper component so that the whole Product component is not re-rendered):
const Product = () => {
const [fetchCounter, setFetchCounter] = useState(0);
return (
<img
src={'imageUrl'}
onError={() => {
if (fetchCounter < 1) {
setFetchCounter(fetchCounter++);
}
}}
/>
)
}
I do not know your use case, but you can load a fallback image instead. It could look something like this:
const Product = () => {
const [imageUrl, setImageUrl] = useState('product-img-url');
return (
<img
src={imageUrl}
onError={() => setImageUrl('fallback-img-url')}
/>
)
}

Can this onPress, called in TochableOpacity, return a Text component?

[
the image is the resultof when you console.log(this.state.fixtures)
I havent run into an error, but also havent gotten a result. Just trying to pass the individual match, from the .map(), to the Card component. Not sure if the onPress should be called in the TouchableOpacity. Been looking at this so a couple of day, any feedback s appreciated. Thank You.
import React, { Component } from 'react';
import { View, Text, TouchableOpacity, LayoutAnimation } from 'react-native';
import { Card, CardSection } from '../common';
//import ListOf from './ListOf';
export default class LeagueCard extends Component {
state ={
fixtures: null
}
componentDidMount = () => {
const {league_name, league_id } = this.props.league
{this.getMatches(league_id)}
}
getMatches = (league_id) => {
let legaueID = league_id
let fixArray = []
//console.log(legaueID)
fetch(`https://apifootball.com/api/?action=get_events&from=2016-10-30&to=2016-11-01&league_id=${legaueID}&APIkey=42f53c25607596901bc6726d6d83c3ebf7376068ff89181d25a1bba477149480`)
.then(res => res.json())
.then(fixtures => {
fixtures.map(function(fix, id){
fixArray =[...fixArray, fix]
})
this.setState({
fixtures: fixArray
})
console.log(this.state.fixtures)
})
}
display = () => {
//console.log(this.state.fixtures)
if(this.state.fixtures != null){
this.state.fixtures.map(function(match, id){
//console.log(match)
return (
<Text>match</Text>
)
})
}
}
render(){
const {league_name, league_id } = this.props.league
return(
<View>
<TouchableOpacity
onPress={() => this.display()}
>
<Card>
<CardSection>
<Text>{league_name}</Text>
</CardSection>
</Card>
</TouchableOpacity>
</View>
)}
}
enter code here
import React, {Component} from 'react';
import {View, Text, TouchableOpacity, LayoutAnimation} from 'react-native';
import {Card, CardSection} from '../common';
export default class LeagueCard extends Component {
constructor(props) {
super(props);
this.state = {
fixtures: null,
matches: []
}
}
componentDidMount() {
const {league_name, league_id} = this.props.league;
this.getMatches(league_id)
};
getMatches = (league_id) => {
let legaueID = league_id;
let fixArray = [];
fetch(`https://apifootball.com/api/?action=get_events&from=2016-10-30&to=2016-11-01&league_id=${legaueID}&APIkey=42f53c25607596901bc6726d6d83c3ebf7376068ff89181d25a1bba477149480`)
.then(res => res.json())
.then(fixtures => {
fixtures.map(function (fix, id) {
fixArray = [...fixArray, fix]
});
this.setState({
fixtures: fixArray
})
})
};
display = () => {
if (this.state.fixtures != null) {
this.setState({
matches: this.state.fixtures.map(match => <Text>{match.country_name}</Text>)
});
}
};
render() {
const {league_name, league_id} = this.props.league;
return (
<View>
<TouchableOpacity onPress={this.display}>
<Card>
<CardSection>
{this.state.matches}
</CardSection>
</Card>
</TouchableOpacity>
</View>
)
}
}
I made the changes I think will render your matches for you. I made your display() f set the state.matches of your LeagueCard, which will now be an array of Text components each displaying match. The Array.prototype.map function in JavaScript returns a new array which should then be used.
Also should mention that I added a constructor where I initialize state, though that is not strictly necessary it is a good practice.
Watch out for typos too, you have one in getMatches which I did not fix.
Edit: I changed match to match.country_name as you can't give objects directly to a Text component. You will need to grab each key/value pair of the object you want to display.
this will not show any error to you, but your components will not render, because react will not know where to render it, a workaround to this problem is try something like this
import React, { Component } from 'react';
import { View, Text, TouchableOpacity, LayoutAnimation } from 'react-native';
import { Card, CardSection } from '../common';
//import ListOf from './ListOf';
export default class LeagueCard extends Component {
state ={
fixtures: null,
showTextList: false
}
componentDidMount = () => {
const {league_name, league_id } = this.props.league
{this.getMatches(league_id)}
}
getMatches = (league_id) => {
let legaueID = league_id
let fixArray = []
//console.log(legaueID)
fetch(`https://apifootball.com/api/?action=get_events&from=2016-10-30&to=2016-11-01&league_id=${legaueID}&APIkey=42f53c25607596901bc6726d6d83c3ebf7376068ff89181d25a1bba477149480`)
.then(res => res.json())
.then(fixtures => {
fixtures.map(function(fix, id){
fixArray =[...fixArray, fix]
})
this.setState({
fixtures: fixArray
})
})
}
display = () => {
//console.log(this.state.fixtures)
this.setState({showTextList: true})
}
render(){
const {league_name, league_id } = this.props.league
return(
<View>
<TouchableOpacity
onPress={() => this.display()}
>
<Card>
<CardSection>
<Text>{league_name}</Text>
{this.state.showTextList && this.state.fixtures &&
this.state.fixtures.map((match, id) => (<Text>{match}</Text>))
}
</CardSection>
</Card>
</TouchableOpacity>
</View>
)}
}
I just put the text list inside your CardSection, because i belive you want to render the list inside it,but feel free to put this wherewver you want

storing data on iOS device using react native

I am new to React Native and trying to create a simple iOS app. The app has a button on clicking which I need to store the timestamp of the click on the device in a file.
I know that React Native has an API called AsyncStorage but I am getting errors while using this. I copied the code from some site on the net.
Can someone please guide me to use this API?
This is my entire code:
import React, {Component} from 'react';
import { StyleSheet, Text, View, TextInput, AsyncStorage } from 'react-native';
export default class App extends Component{
state = {
'name': ''
}
componentDidMount = () => AsyncStorage.getItem('name').then((value) => this.setState({'name': value}))
setName = (value) => {
AsyncStorage.setItem('name': value);
this.setState({'name': value});
}
render() {
return (
<View style={styles.container}>
<TextInput style = {styles.textInput} autoCapitalize = 'none'
onChangeText = {this.setName}/>
<Text>
{this.state.name}
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
marginTop: 50
},
textInput: {
margin: 15,
height: 35,
borderWidth: 1,
backgroundColor: '#7685ed'
}
});
As for the error, when I launch the code on iOS, I am getting a red screen. There is no syntax error that I can see.
Thanks in advance.
Hard to say without more detail the exact problem you're facing, but I assume some of the following might help you?
Ah I see you posted some code. You will need a constructor that defines your state as well. Added it in my code below.
Please note I'm not an expert. Forgive any errors
import {
AsyncStorage,
} from 'react-native';
class myComponent extends React.Component{
constructor(props) {
super(props);
this.state = {
data: null
};
}
componentDidMount() {
this._loadInitialState().done();
}
_someFunction() {
var myData = 123;
saveItemLocally('data', myData);
}
async _loadInitialState() {
try {
// get localy stored data
var dataStored = await AsyncStorage.getItem('data');
if (dataStored!==null) {
this.setState({
data: dataStored
});
}
} catch (error) {
//didn't get locally stored data
console.log(error.message);
}
} // end _loadinitialstate
render () {
//your render function
return (
);
}
} // end of your component
async function saveItemLocally(item, value) {
try {
await AsyncStorage.setItem(item, value);
} catch (error) {
console.log('AsyncStorage error: ' + error.message);
}
}

Why react doesn't show Image from url local

hello every one I have an application running locally with RoR everything works fine in the backend, also I can see the Json in Postman
http://127.0.0.1:3000/api/v1/articles
[
{
"id": 1,
"title": "Barack Obama",
"description": "Sabias que? el era muy pobre",
"avatar_content_type": "/system/articles/avatars/000/000/001/original/user-two.png?1509755893"
}
]
and also in my mobile emulator I can see the Title and description that's mean everything works fine. BUT I can't see the image :/ some advice?
ProductList.js
// step 1: import libraries
import React, { Component } from 'react';
import { ScrollView } from 'react-native';
import Product from './Product';
export default class ProductList extends Component {
state = {
products: []
}
componentDidMount() {
return fetch('http://MYIP:3000/api/v1/articles')
.then((response) => response.json())
.then((responseJson) => {
this.setState({products: responseJson})
})
}
render() {
var productList = this.state.products.map(function(item) {
return (
<Product title = { item.title }
description = { item.description }
image_url = { item.avatar_content_type }
key = { item.id }/>
)
})
return (
<ScrollView>
{ productList }
</ScrollView>
);
}
}
Product.js
// step 1: import libraries
import React, { Component } from 'react';
import { StyleSheet, Text, View, Alert, Image } from 'react-native';
// step 2: create component
export default class Product extends Component {
render() {
return (
<View>
<Image source={{uri: this.props.image_url }} style={{width: 60,height: 60,}}/>
<Text style = { style.textStyle }>{ this.props.title }</Text>
<Text style = { style.textStyle }>{ this.props.description }</Text>
</View>
);
}
}
const style = StyleSheet.create({
textStyle: {
fontSize: 20,
padding: 20
},
amountStyle: {
fontSize: 15,
paddingLeft: 20
}
})
I dont get exceptions or something similar, I'm not just be able to see the Image in my mobile emulator
It may be because It is empty during the first render as you are trying to perform an asynchronous operation
So what you could do is u can check by giving a condition I normally do it with lodash using _.isEmpty method
try this:
<Image source={{uri: (_.isEmpty(this.props.image_url) ? null : this.props.image_url) }}

maximum call stack size exceeded react native

hi my dear friends i have problem in my simple code in react native
when i run the code i` giving this error. apologize i'm nub in react native :)
import React, { Component } from 'react';
import {
ListView,
View
} from 'react-native';
import MyPresentationalComponent1 from './MyPresentationalComponent1'
export default class MyContainerComponent extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !==
r2});
this.state = {
dataSource: ds.cloneWithRows([
'Item1', 'Item2', 'Item3', 'Item4', 'Item5', 'Item6', 'Item7',
'Item8',
'Item9', 'Item10'
])
};
}
render() {
return (
<View>
<MyPresentationalComponent1 dataSource = {this.state.dataSource}/>
</View>
);
}
}`

Resources