React Native AsyncStorage not getting the value - react-native

constructor(props) {
super(props);
this.state = { data: '' } ;
}
componentWillMount = () => AsyncStorage.getItem('restaurants').then((value) => this.setState({data: value}))
return (
<View>
{this.state.data.map((item) => {
return (
<View>
<Text> {item.name} </Text>
<Text> {item.time} </Text>
</View>
)
})
}
</View>
)
I am trying to get the value in the AsyncStorage, but i keep getting the error: undefined is not a function(evaluating 'this.state.data.map). I been searching the similar topic for a while but I did not find any solution to it. Can someone show me an correct example to do it? Thanks

If You Have stored data in this way
storeData = async () => {
try {
var data ={
restaurants: [
{
name: 'MacD ',
time: "Morning"
},
{
name: 'PizzaHouse',
time: "Evening"
}
]
}
await AsyncStorage.setItem('restaurants', JSON.stringify(data.restaurants))
} catch (error) {
// Error saving data
}
}
constructor(props) {
super(props);
this.state={
fetchingData: true,
data: []
}
}
getData = async()=>{
try {
data = await AsyncStorage.getItem('restaurants');
this.setState({fetchingData: false , data:JSON.parse(data)})
} catch(error){
console.log(error)
}
}
componentDidMount(){
this.getData();
}
renderRestaurant(){
return this.state.data.map((item) => {
return (
<View>
<Text> {item.name} </Text>
<Text> {item.time} </Text>
</View>
)
})
}
render() {
return (
<View style={{width:200, height:200, justifyContent:'center', alignItems:'center', backgroundColor:"blue"}}>
{this.state.fetchingData ? null : this.renderRestaurant()}
</View>
);
};

Try await before AsyncStorage, similar to that or inline
componentWillMount (){
const rest = await AsyncStorage.getItem('restaurants');
}

Related

How to cache data and fetch in reactnative?

I am new to Reactnative and Javascript and I am trying to cache the data from APi and get it. But it is not working. I could not render the data. I am getting the error. How can I cache and retrieve data from cache when there is no internent? I have implemented the code for caching as follows:
export default class ViewpagerP extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, data: [] }
}
async componentDidMount() {
const photoStorage = await AsyncStorage.getItem('GalleryPhotos')
console.log(photoStorage);
if(!photoStorage) {
try {
console.log("Null inside")
const photoResp = await axios.get('https://rallycoding.herokuapp.com/api/music_albums')
console.log(photoResp)
const photoData = await JSON.stringify(photoResp.data);
this.setState({data:photoResp,isLoading:false})
await AsyncStorage.setItem('GalleryPhotos', photoData);
} catch(e) {
console.warn("fetch Error: ", error)
}
then(response => this.setState({ data: response.data,isLoading:false }))
}else{
this.getPhotos;
}
}
getPhotos = async()=> {
try {
data = JSON.parse(await AsyncStorage.getItem('GalleryPhotos'));
this.setState({data:data,isLoading:false})
console.log(data);
}
catch (error) {
console.error(error);
}
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator />
</View>
)
}
console.log(this.state.data);
return (
<View style={styles.container}>
<ImageSlider style={styles.viewPagerStyle}
loopBothSides
autoPlayWithInterval={6000}
images={this.state.data}
customSlide={({ index, item, style, width }) => (
<View key={index} style={[style, styles.customSlideStyle]}>
<View style={styles.contentContainer}>
<Image source={{ uri: item.image }} style={styles.customImage} />
<View style={styles.textContainerStyle}>
<Text style={styles.textStyle}>{item.title}</Text>
</View>
</View>
</View>
)
}
/>
</View>
);
}
}
You need some correction in code
this.getPhotos;
to
this.getPhotos();
And also you can check internate is on off by using
import { NetInfo} from 'react-native';
Check the below artical it will help you
enter link description here
here is come correction
export default class ViewpagerP extends Component {
constructor(props) {
super(props);
this.state = { isLoading: true, data: [] }
}
async componentDidMount() {
const photoStorage = await AsyncStorage.getItem('GalleryPhotos')
console.log(photoStorage);
if(!photoStorage) {
try {
console.log("Null inside")
const photoResp = await axios.get('https://rallycoding.herokuapp.com/api/music_albums')
console.log(photoResp)
const photoData = await JSON.stringify(photoResp.data);
this.setState({data:photoResp,isLoading:false})
await AsyncStorage.setItem('GalleryPhotos', photoData);
} catch(e) {
console.warn("fetch Error: ", error)
}
}else{
this.getPhotos();
}
}
getPhotos = async()=> {
try {
data = JSON.parse(await AsyncStorage.getItem('GalleryPhotos'));
this.setState({data:data,isLoading:false})
console.log(data);
}
catch (error) {
console.error(error);
}
}
render() {
if (this.state.isLoading) {
return (
<View style={{ flex: 1, padding: 20 }}>
<ActivityIndicator />
</View>
)
}
console.log(this.state.data);
return (
<View style={styles.container}>
<ImageSlider style={styles.viewPagerStyle}
loopBothSides
autoPlayWithInterval={6000}
images={this.state.data}
customSlide={({ index, item, style, width }) => (
<View key={index} style={[style, styles.customSlideStyle]}>
<View style={styles.contentContainer}>
<Image source={{ uri: item.image }} style={styles.customImage} />
<View style={styles.textContainerStyle}>
<Text style={styles.textStyle}>{item.title}</Text>
</View>
</View>
</View>
)
}
/>
</View>
);
}
}

Redux didn't update component

I'm pretty new in React-Native. I'm trying to display a list of devices, then go to one device, go to its informations, change the name, and with redux to change the name on all "screens" but it didn't work. I thing I a little bit lost between props, state and global state...
All the navigation, views and APIs works well.
This is my list view:
class DeviceList extends React.Component {
constructor(props) {
super(props);
this.state = {
isLoading: true,
};
this._getDevices();
// BINDING
this._goToDevice = this._goToDevice.bind(this);
this._goToDeviceAdd = this._goToDeviceAdd.bind(this);
}
componentDidUpdate() {
console.log("DEVICE_LIST componentDidUpdate : ");
console.log(this.props.devices);
}
_goToDevice(id = number) {
this.props.navigation.navigate('DeviceDetail', { idDevice: id })
}
_getDevices() {
restGet('devices')
.then(data => {
// REDUX
const action = { type: "INIT_DEVICE_LIST", value: data.datas };
this.props.dispatch(action);
// STATE
this.setState({
isLoading: false
});
});
}
_displayList() {
if (!this.state.loading && this.props.devices && this.props.devices.length > 0) {
return (
<View style=>
<FlatList
// data={this.state.devices}
data={this.props.devices}
keyExtractor={(item) => item.id.toString()}
renderItem={({item}) => <DeviceItem device={item} goToDevice={this._goToDevice}
/>}
/>
</View>
)
}
}
render() {
return (
<View style={styles.main_container}>
{/* LOADING */}
<Loading loading={this.state.isLoading}/>
{/* LIST */}
{this._displayList()}
</View>
);
}
}
// REDUX
const mapStateToProps = (state) => {
return {
devices: state.devices
};
};
export default connect(mapStateToProps)(DeviceList);
This is my Device Detail screen:
class DeviceDetail extends React.Component {
constructor(props) {
super(props);
this.state = {
device: null,
isLoading: true,
};
//
this._getDevice();
}
componentDidUpdate() {
console.log("DEVICE_DETAIL componentDidUpdate : ");
console.log(this.props.devices);
}
_goToDeviceInfo() {
this.props.navigation.navigate('DeviceInfo', { deviceId: this.state.device.id })
}
_getDevice() {
restGet('devices/' + this.props.navigation.getParam('idDevice'))
.then(data => {
// REDUX
const action = { type: "UPDATE_DEVICE", value: data.datas };
this.props.dispatch(action);
// STATE
this.setState({
device: this.props.devices.find(d => d.id === this.props.navigation.getParam('idDevice')),
isLoading: false,
});
});
}
_displayTile() {
if (this.state.device) {
return (
<View>
<Text>{this.state.device.name}</Text>
<TouchableOpacity onPress={() => this._goToDeviceInfo()}>
<FontAwesomeIcon icon={ faCog } size={ 18 } />
</TouchableOpacity>
</View>
)
}
}
render() {
return (
<View style={styles.main_container}>
{/* LOADING */}
<Loading loading={this.state.isLoading}/>
{/* TILE */}
{this._displayTile()}
</View>
);
}
}
// REDUX
const mapStateToProps = (state) => {
return {
devices: state.devices
};
};
export default connect(mapStateToProps)(DeviceDetail);
My Device Info Screen
class DeviceInfo extends React.Component {
constructor(props) {
super(props);
this.state = {
// device: this.props.navigation.getParam('device')
// device: this.props.devices.find(d => d.id === this.props.navigation.getParam('deviceId')),
};
// BINDING
this._saveItem = this._saveItem.bind(this);
}
componentDidUpdate() {
console.log("DEVICE_INFO componentDidUpdate : ");
console.log(this.props.devices);
}
_saveItem(name) {
// DB
// restPost('devices', {'id': this.state.device.id, 'name': name})
console.log();
restPost('devices', {'id': this.props.devices.find(d => d.id === this.props.navigation.getParam('deviceId')).id, 'name': name})
.then(data => {
// REDUX
const action = { type: "UPDATE_DEVICE", value: data.datas };
this.props.dispatch(action);
});
}
_removeDevice() {
Alert.alert(
'Supprimer l\'Appareil',
'Voulez-vous vraiment supprimer cet Appareil ?',
[
{
text: 'Annuler',
style: 'cancel',
onPress: () => console.log('Cancel Pressed'),
},
{
text: 'Oui, je souhaite le supprimer.',
onPress: () => {
// REDUX
const action = { type: "DELETE_DEVICE", value: this.state.device };
this.props.dispatch(action);
this.props.navigation.navigate('DeviceList')
}
},
],
{cancelable: false},
);
}
render() {
// const device = this.state.device;
const device = this.props.devices.find(d => d.id === this.props.navigation.getParam('deviceId'));
return (
<View style={ styles.main_container }>
<DeviceInfoItem device={device} title={'NOM'} value={device.name} edit={true} saveItem={this._saveItem}/>
<View style={styles.footer}>
<TouchableOpacity style={styles.startButton} onPress={() => this._removeDevice()}>
<FontAwesomeIcon icon={ faTrash } style={styles.footer_element_icon}/>
<Text style={styles.footer_element_text}>Supprimer l'Appareil</Text>
</TouchableOpacity>
</View>
</View>
);
}
}
// REDUX
const mapStateToProps = (state) => {
return {
devices: state.devices
};
};
export default connect(mapStateToProps)(DeviceInfo);
My Device Info Item Component
class DeviceInfoItem extends React.Component {
constructor(props) {
super(props);
this.state = {
displayForm: false,
};
this.editText = '';
console.log(this.props);
}
componentDidUpdate() {
console.log("DEVICE_INFO_ITEM componentDidUpdate");
}
_displayValue() {
if (this.props.edit && this.state.displayForm) {
return (
<View>
<Input
placeholder={this.props.title}
// value={value}
leftIcon={<FontAwesomeIcon icon={ faTag } size={ 10 } />}
leftIconContainerStyle={ styles.inputIcon }
onChangeText={(text) => {
this.editText = text;
}}
/>
</View>
);
} else {
return (
<View>
<Text style={ styles.title }>{ this.props.title }</Text>
<Text style={ styles.value }>{ this.props.value }</Text>
</View>
);
}
}
_displayButton() {
if (this.props.edit) {
if (!this.state.displayForm) {
return (
<TouchableOpacity style={styles.edit} onPress={() => {
this.setState({
displayForm: true
})
}}>
<FontAwesomeIcon icon={ faPen } style={ styles.info_icon } size={ 14 } />
</TouchableOpacity>
);
} else {
return (
<TouchableOpacity style={styles.edit} onPress={() => {
this.props.saveItem(this.editText);
this.setState({
displayForm: false,
});
}}>
<FontAwesomeIcon icon={ faCheck } style={ styles.info_icon } size={ 14 } />
</TouchableOpacity>
);
}
}
}
render() {
return (
<View>
<View style={ styles.line }>
{ this._displayValue() }
{ this._displayButton() }
</View>
<Divider style={ styles.divider } />
</View>
);
}
}
export default DeviceInfoItem;
And my reducer:
const initialState = {
devices: []
};
function updateDevices(state = initialState, action) {
let nextState;
// CHECK IF DEVICE EXIST
const deviceIndex = state.devices.findIndex(device => device.id === action.value.id);
let device = state.devices.find(device => device.id === action.value.id);
switch (action.type) {
case 'INIT_DEVICE_LIST':
console.log('INIT_DEVICE_LIST');
nextState = {
...state,
devices: action.value
};
return nextState || state;
case 'ADD_DEVICE':
console.log('ADD_DEVICE');
nextState = {
...state,
devices: [...state.devices, action.value]
};
return nextState || state;
case 'DELETE_DEVICE':
console.log('DELETE_DEVICE');
if (deviceIndex !== -1) {
nextState = {
...state,
devices: state.devices.filter( (item, index) => index !== deviceIndex)
}
}
return nextState || state;
case 'UPDATE_DEVICE':
console.log('UPDATE_DEVICE');
if (deviceIndex !== -1) {
let d = state.devices;
d[deviceIndex] = action.value;
nextState = {
...state,
devices: d
}
}
return nextState || state;
default:
return state
}
}
export default updateDevices;
Delete Device works very well, the devices list in well updated. But the name updating didn't work. When I save, I got a console log ('DEVICE_INFO_ITEM componentDidUpdate) but not ('DEVICE_INFO componentDidUpdate). Why ?
create a file index.js in your reducer folder and do this:
import { combineReducers } from 'redux';
import myreducer from './Reducerfile';
export default combineReducers({
reducer: myreducer
});
And then
// REDUX
const mapStateToProps = (state) => {
return {
devices: state.reducer.devices
};
};
export default connect(mapStateToProps)(DeviceInfo);

Why react-native doesn't render all content when 2 render methods included in it?

I have some content to be rendered conditionally and some fixed content i.e. footer. I dont want to render footer every time when state changes, hence I've added two methods renderContent() and renderFooter to be called in render() method.
Below code, doesn't render both methods.
'use strict';
import React, { Component } from 'react';
import { Alert, FlatList, View, StyleSheet, Text, Linking, Button } from 'react-native';
import { AsyncStorage } from 'react-native';
import getEnvVars from '../environment';
const { apiUrl } = getEnvVars();
import Moment from 'moment';
import { Ionicons } from '#expo/vector-icons';
import FootBar from '../screens/FootBar';
import { LinesLoader } from 'react-native-indicator';
export default class SubscriptionsToEnd extends Component {
static navigationOptions = ({ navigation }) => {
const { state } = navigation;
return {
title: `${state.params && state.params.title ? state.params.title : 'Subscriptions Due'}`,
};
};
constructor(props) {
super(props);
this.state = {
isLoaded: false,
dataSource: [],
title: 'Subscriptions Due'
};
}
componentDidMount() {
this._getAllCustomers();
}
_getAllCustomers() {
let url;
if (this.state.title === 'Subscriptions Due') {
url = apiUrl + "/customersWithSubscriptionNearToEnd/";
this.props.navigation.setParams({ title: 'Subscriptions Due' })
}
if (this.state.title === 'Customers') {
url = apiUrl + "/customers/";
this.props.navigation.setParams({ title: 'Customers' })
}
this.setState({ isLoaded: false })
try {
AsyncStorage.multiGet(['role', 'jwt']).then((data) => {
let role = data[0][1];
let jwt = data[1][1];
if (role === 'Admin') {
fetch(url, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
'jwt': jwt
},
}).then(res => res.json())
.then(
(result) => {
if (result.message != 'Unauthorized user!' && this.state.title === 'Customers') {
this.setState({
isLoaded: true,
dataSource: result,
title: 'Subscriptions Due'
});
} else if (result.message != 'Unauthorized user!' && this.state.title === 'Subscriptions Due') {
this.setState({
isLoaded: true,
dataSource: result,
title: 'Customers'
});
} else if (result.message === 'Unauthorized user!') {
this.props.navigation.navigate('Login');
}
},
(error) => {
console.log(error);
this.setState({
isLoaded: true
});
this.props.navigation.navigate('Login');
}
)
}
})
} catch (error) {
console.log('Error at getting token \n' + error)
}
}
GetGridViewItem(id) {
Alert.alert(id);
}
_logOutAsync = async () => {
await AsyncStorage.clear();
this.props.navigation.navigate('Auth');
};
_addCustomer() {
// TBD
}
renderContent() {
if (!this.state.isLoaded) {
return (
<View style={styles.loader}>
<LinesLoader color='#1d91a5' barWidth={5} barHeight={60} barNumber={5} betweenSpace={5} />
</View>
)
}
if (this.state.isLoaded) {
return (
<View style={styles.container}>
<View style={styles.grid}>
<FlatList
data={this.state.dataSource}
renderItem={({ item }) =>
<View style={styles.GridViewContainer}>
<Text style={styles.GridViewTextLayout}>
<Text onPress={this.GetGridViewItem.bind(this, item._id)}>
<Text style={styles.Name}>{item.firstname}</Text> <Text style={styles.Name}>{item.lastname}</Text> {"\n"}
<Text>{Moment(item.till_date).format('Do MMM YYYY')} </Text>{"\n\n"}
</Text>
<Text onPress={() => { Linking.openURL('tel:+44' + item.mobile); }}><Ionicons name="md-phone-portrait" size={22} color="#1d91a5" /> {item.mobile}</Text> {"\n\n"}
<Text><Ionicons name="md-mail" size={22} color="#1d91a5" />{item.email}</Text>
</Text>
</View>}
numColumns={2}
keyExtractor={(item, index) => index.toString()}
/>
</View >
</View>
)
};
}
renderFooter() {
return (
<View style={styles.buttonsContainer}>
<View style={styles.button}>
<Button color='#1d91a5' title={this.state.title} onPress={this._getAllCustomers.bind(this)} />
</View>
<View style={styles.button}>
<Button color='#1d91a5' title="+Customer" onPress={this._addCustomer.bind(this)} />
</View>
<View style={styles.button}>
<Button color='#1d91a5' title="Logout" onPress={this._logOutAsync.bind(this)} />
</View>
</View>
);
}
render() {
return (
this.renderContent(),
this.renderFooter()
);
}
}
Above code only renders this.renderFooter() method. If I swap methods in render(), it renders this.renderContent().
Can someone please tell me why it is failing to render both?
I was doing it wrong. Main render() method should be like:
render() {
return (
<View style={styles.wrapper}>
{this.renderContent()}
{this.renderFooter()}
</View>
);
}
It looks like you figured it out just before I could post my answer.
The return function can only return one view. Your 2 functions each return a view. So wrapping both functions in a single view solves the problem.

Update props from other component in react native

I have a Main class which I show an array to user, then in detail page user can edit each element which I'm passing using react navigation parameter. I want to edit my array in the detail class and save it using async storage.
//Main.jsimport React from 'react';
import {
StyleSheet ,
Text,
View,
TextInput,
ScrollView,
TouchableOpacity,
KeyboardAvoidingView,
AsyncStorage
} from 'react-native'
import Note from './Note'
import detail from './Details'
import { createStackNavigator, createAppContainer } from "react-navigation";
export default class Main extends React.Component {
static navigationOptions = {
title: 'To do list',
headerStyle: {
backgroundColor: '#f4511e',
},
};
constructor(props){
super(props);
this.state = {
noteArray: [],
noteText: '',
dueDate: ''
};
}
async saveUserTasks(value) {
try {
await AsyncStorage.setItem('#MySuperStore:userTask',JSON.stringify(value));
} catch (error) {
console.log("Error saving data" + error);
}
}
getUserTasks = async() =>{
try {
const value = await AsyncStorage.getItem('#MySuperStore:userTask');
if (value !== null){
this.setState({ noteArray: JSON.parse(value)});
}
} catch (error) {
console.log("Error retrieving data" + error);
}
}
render() {
this.getUserTasks()
let notes = this.state.noteArray.map((val,key) => {
return <Note key={key} keyval={key} val={val}
deleteMethod={ () => this.deleteNote(key)}
goToDetailPage= {() => this.goToNoteDetail(key)}
/>
});
const { navigation } = this.props;
return(
<KeyboardAvoidingView behavior='padding' style={styles.keyboard}>
<View style={styles.container}>
<ScrollView style={styles.scrollContainer}>
{notes}
</ScrollView>
<View style={styles.footer}>
<TextInput
onChangeText={(noteText) => this.setState({noteText})}
style={styles.textInput}
placeholder='What is your next Task?'
placeholderTextColor='white'
underlineColorAndroid = 'transparent'
>
</TextInput>
</View>
<TouchableOpacity onPress={this.addNote.bind(this)} style={styles.addButton}>
<Text style={styles.addButtonText}> + </Text>
</TouchableOpacity>
</View>
</KeyboardAvoidingView>
);
}
addNote(){
if (this.state.noteText){
var d = new Date();
this.state.noteArray.push({
'creationDate': d.getFullYear() + "/" + (d.getMonth()+1) + "/" + d.getDay(), 'taskName': this.state.noteText,'dueDate':'YYYY/MM/DD'
});
this.setState({noteArray:this.state.noteArray})
this.setState({noteText: ''});
this.saveUserTasks(this.state.noteArray)
}
}
deleteNote(key){
this.state.noteArray.splice(key,1);
this.setState({noteArray: this.state.noteArray})
this.saveUserTasks(this.state.noteArray)
}
goToNoteDetail=(key)=>{
this.props.navigation.navigate('DetailsScreen', {
selectedTask: this.state.noteArray[key],
});
}
}
in detail view I have this method which is similar to add note in main class:
export default class Details extends React.Component {
render() {
const { navigation } = this.props;
const selectedTask = navigation.getParam('selectedTask', 'task');
return(
<View key={this.props.keyval} style={styles.container}>
<TouchableOpacity onPress={this.saveEdit.bind(this)} style={styles.saveButton}>
<Text style={styles.saveButtonText}> save </Text>
</TouchableOpacity>
</View>
);
}
saveEdit(){
let selectedItem = { 'creationDate': selectedTask['creationDate'],
'taskName': selectedTask['taskName'],
'dueDate': this.state.dueData}
this.props.navigation.state.params.saveEdit(selectedItem)
}
}
How can I change my props in any component?
First of all you shouldn't call this.getUserTasks() in the render method because the function has this.setState which is bad and could end in a endless loop I guess or at least effect in worse performance. You could instead call it in componentDidMount:
componentDidMount = () => {
this.getUserTasks();
}
Or alternatively call already in constructor but I prefer the first option:
constructor(props){
super(props);
this.state = {
noteArray: [],
noteText: '',
dueDate: ''
};
this.getUserTasks()
}
this.props.noteArray.push({.. is probably undefined because you aren't passing it down any where. (Didn't see any reference in your snippet). I guess I would implement the saveEdit function in the Main.js component and simply pass it down to the navigation route and call the function in Details component by accessing the navigation state props:
Update
goToNoteDetail=(key)=>{
this.props.navigation.navigate('DetailsScreen', {
// selectedTask: this.state.noteArray[key],
selectedItem: key,
saveEdit: this.saveEdit
});
}
saveEdit(selectedItem){
const selectedTask = this.state.noteArray[selectedItem]
this.state.noteArray.push({
'creationDate': selectedTask['creationDate'],
'taskName': selectedTask['taskName'],
'dueDate': this.state.dueData
});
this.setState({noteArray:this.state.noteArray})
this.setState({dueData: 'YYYY/MM/DD'});
this.saveUserTasks(this.state.noteArray)
}
And then call saveEdit in Details Component:
saveSelectedItem = () => {
const { navigation } = this.props.navigation;
const {selectedItem, saveEdit} = navigation.state && navigation.state.params;
saveEdit(selectedItem)
}

fetch data from api row counter

By use of the following Code we can read Data from Server:
class SearchPage extends Component {
constructor(props) {
super(props);
var dataSource = new ListView.DataSource({rowHasChanged:(r1,r2) => r1.ruid != r2.guid});
this.state = {
id: 'SearchPage',
searchinpt: this.props.homesearchinpt,
shopid: this.props.shopid,
dataSource: dataSource.cloneWithRows(shopsArray),
isLoading: true
};
}
componentDidMount(){
this.fetchData();
}
fetchData() {
var name = this.state.searchinpt;
var API_URL = 'http://myurl';
var PARAMS = '?name=' + name;
var REQUEST_URL = API_URL + PARAMS;
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData),
loaded: true,
});
})
.done();
}
renderLoadingView() {
return (
<View style={styles.container}>
<Text>Loading</Text>
</View>
);
}
SearchisEmpty() {
return (
<View style={styles.container}>
<Text style={styles.notfound}>Not Found</Text>
</View>
);
}
SearchnotEmpty(){
return (
<ListView enableEmptySections = {true}
dataSource={this.state.dataSource}
renderRow=
{(shop) =>
<TouchableOpacity
onPress={(shop_id) => this.onSubmitPressed(shop.shop_id)} >
<View style={styles.container} >
<Image
source={{uri: shop.shop_logo}}
style={{width: 50, height: 50}}>
</Image>
<View>
<Text style={styles.shop_name}>{shop.shop_name}</Text>
<Text style={styles.shop_description}>{shop.shop_description}</Text>
</View>
</View>
<Text>{this.state.searchinpt}</Text>
<Text>{this.state.dataSource.getRowCount}</Text>
</TouchableOpacity>
}
style={styles.listView}
/>
);
}
onSubmitPressed(shopd){
this.props.navigator.push({
id: 'Shop',
passProps:{
thisshopid: shopd
}
})
}
render(shopsArray) {
if (!this.state.loaded) {
return this.renderLoadingView();
}else if(this.state.length < 1){
return this.SearchisEmpty();
} else{
return this.SearchnotEmpty();
}
}
}
There isn't any problem for Render.
Now we have some "if" that Whenever there isn't any Data, must show "Not found", But instead of (Not Found) it shows blank page
How can I solve the problem?
this.state.length will always be undefined as this.state is an object, not an array.
I would store the number of rows in the state to be able to control this behaviour. Something like this:
...
fetchData() {
...
fetch(REQUEST_URL)
.then((response) => response.json())
.then((responseData) => {
this.setState({
dataSource: this.state.dataSource.cloneWithRows(responseData),
loaded: true,
numRows: responseData.length
});
})
.done();
}
...
render(shopsArray) {
if (!this.state.loaded) {
return this.renderLoadingView();
}else if(this.state.numRows < 1){
return this.SearchisEmpty();
} else{
return this.SearchnotEmpty();
}
}