Flatlist is not reading "data" variable set using hooks in react native - react-native

I'm using hooks in react native project and setting data variable with referenced firebase database, when I'm console logging this data variable, It is showing null at first and within few seconds it shows fetched data, but flatlist is not reading it. Please correct my mistake. Here is my code:
RecommenTab = () => {
useFirebaseQuery = ref => {
const [docState, setDocState] = useState({
isLoading: true,
data: null
});
useEffect(() => {
return ref.on("value", snapshot => {
setDocState({
isLoading: false,
data: snapshot
});
});
}, []);
return docState;
};
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: "86%",
backgroundColor: "#CED0CE",
marginLeft: "14%"
}}
/>
);
};
userList = () => {
const ref = database.ref("users");
const { isLoading, data } = this.useFirebaseQuery(ref);
if (data != []) {
return (
<SafeAreaView style={{ marginTop: 20 }}>
{console.log(data)}
<Text>SHOW</Text>
<FlatList
data={data}
renderItem={({ item }) => (
<View>
<Text>Work</Text>
<ListItem
title={item.name}
subtitle={item.username}
leftAvatar={{
rounded: true,
source: { uri: item.avatar }
}}
/>
</View>
)}
keyExtractor={item => item.id}
ItemSeparatorComponent={this.renderSeparator}
/>
</SafeAreaView>
);
}
};
return <View>{this.userList()}</View>;
};

Related

How do I add items to array in following format and display it in flatlist?

I am trying to add items to redux state array. I can add items but my flatlist doesn't display them. It's most likely because they are like this ['abc-123, bcd-234'] etc. instead of [{license: abc-123}] so I could call the item.license in my flatlist. And how would I add an id to these items. How can I fix my structure a bit to get the [{id: 0, license: 'abc-123'}] ?
This is my action file:
const ADD_NEW_CAR = 'ADD_NEW_CAR'
const DELETE_EXISTING_CAR = 'DELETE_EXISTING_CAR'
export const addNewCar = (text) => ({
type: ADD_NEW_CAR,
payload: text
})
export const deleteExistingCar = (license) => ({
type: DELETE_EXISTING_CAR,
payload: license
})
this is my reducer:
const ADD_NEW_CAR = 'ADD_NEW_CAR'
const DELETE_EXISTING_CAR = 'DELETE_EXISTING_CAR'
const initialState = {
cars: [],
}
const carsListReducer = (state = initialState, action) => {
switch (action.type) {
case ADD_NEW_CAR:
return {
...state,
cars: [...state.cars, action.payload],
}
case DELETE_EXISTING_CAR:
return {
cars: [
...state.cars.filter(license => license !== action.payload)
]
}
default:
return state
}
}
export default carsListReducer
and this is my flatlist:
const totalCars = props.cars.length
<FlatList
style={{ marginTop: 0 }}
data={cars}
keyExtractor={(item) => item.id}
renderItem={({ item }) => {
return (
<View style={licenseContainer}>
<View style={{ width: '20%' }}>
<Ionicons
style={carIcon}
name='car-outline'
size={30}
color={colors.black}
/>
</View>
<View style={{ width: editing ? '60%' : '80%' }}>
<Text key={item.license} style={licenseText}>
{item.license}
</Text>
</View>
{editing ? (
<View style={{ width: '20%' }}>
<Ionicons
name='ios-close-circle-outline'
size={30}
color={colors.black}
style={removeIcon}
onPress={() => removeCar(item.license)}
/>
</View>
) : null}
</View>
)
}}
ItemSeparatorComponent={() => {
return <View style={divider} />
}}
/>
const mapStateToProps = (state) => ({
signedIn: state.authReducer.signedIn,
cars: state.cars
})
const mapDispatchToProps = (dispatch) => ({
authActions: bindActionCreators(authAction, dispatch),
addNewCar: text => dispatch(addNewCar(text)),
deleteExistingCar: car => dispatch(deleteExistingCar(car))
})
export default connect(mapStateToProps, mapDispatchToProps)(ProfileScreen)
If your array contains string values then instead of using item.license just use item
<View style={{ width: editing ? '60%' : '80%' }}>
<Text key={item} style={licenseText}>
{item}
</Text>
</View>

Use global variable to generate a dynamic url (React Native)

I have a datapicker where I select the country and with this I create a url.
<View style={styles.centrado}>
<Text style={styles.seleccion}>Elige tu País</Text>
{this.Paises()}
<Picker
selectedValue={this.state.value || ""}
style={{ height: 50, width: 120 }}
itemStyle={styles.seleccion}
onValueChange={(value, idx) => {
this.setState({ value, idx });
global.Pais = value;
console.log({ valor: value });
this.props.navigation.navigate("Noticias", {
pais: value
});
}}
>
<Picker.Item label="Seleccione" value="" />
<Picker.Item label="Argentina" value="ar" />
<Picker.Item label="Bolivia" value="bo" />
</Picker>
</View>
In the first load everything works but when I return to the home and select another country the global (global.Pais) variable remains with the initial value.
export default class noticias extends React.Component {
state = {
loading: true,
noticias: []
};
constructor(props) {
super(props);
this.fetchNoticias();
}
fetchNoticias = async () => {
console.log(global.Pais);
if (!global.Pais || global.Pais == "undefined") {
alert("Selecciona un país para ver las noticias");
this.props.navigation.navigate("Home");
} else if (global.Pais == "uy") {
const response = await fetch(
`https://prueba.${global.Pais}/wp-json/wp/v2/posts`
);
const res = await response.json();
this.setState({ noticias: res, loading: false });
} else {
const response = await fetch(
`https://prueba.com.${global.Pais}/wp-json/wp/v2/posts`
);
const res = await response.json();
this.setState({ noticias: res, loading: false });
}
};
componentDidMount() {
this.fetchNoticias();
}
render() {
const { loading, noticias } = this.state;
if (loading) {
return (
<View style={styles.container}>
<Text>Cargando .....</Text>
</View>
);
}
return (
<View>
<FlatList
data={this.state.noticias}
keyExtractor={(x, i) => i.toString()}
renderItem={({ item }) => (
<View>
<TouchableOpacity
onPress={() =>
this.props.navigation.navigate("Noticia", {
post_id: item.id
})
}
>
<Card
style={{
shadowOffset: { width: 5, height: 5 },
width: "90%",
borderRadius: 12,
alignSelf: "center",
marginBottom: 10
}}
>
<Card.Content>
<Title>{item.title.rendered}</Title>
</Card.Content>
<Card.Cover
source={{
uri:
item.better_featured_image.media_details.sizes.medium
.source_url
}}
/>
<Card.Content>
<HTMLRender html={item.excerpt.rendered} />
</Card.Content>
</Card>
</TouchableOpacity>
</View>
)}
/>
</View>
);
}
}
How can I solve it?
I think that won't work, you could use react-context or redux to save and update that value or
this.props.navigation.setParams({ pais: value })
and then get that value when you need it
this.props.navigation.getParam('pais')

stop activity indicator when all data has been fetched from server

I'm getting activity indicator after 20 posts as the offset number is set to 20 and after each scroll its loading more content but I want it to stop loading (Activity Indicator) when reached at the end of the data and there is no data to fetch.
Here is all the default states:
this.state = {
data: [],
dataProvider: new DataProvider((item1, item2) => {
return item1.ID !== item2.ID;
}),
isLoading: false,
};
Here is the render of the component:
render(){
if( !this.state.data.length ) {
return(
<ActivityIndicator
style={{flex: 1, justifyContent: 'center', alignItems: 'center'}}
size='large'
color='#0A80FE'
/>
);
}
return(
<>
<View style={{flex:1}}>
<RecyclerListView
style={{ flex: 1 }}
onEndReached={() => {
this.getData();
//(ignore this as this is required for recyclerlist view)
this.setState({});
}}
onEndReachedThreshold={1000}
dataProvider={this.state.dataProvider}
rowRenderer={this.renderItem}
renderFooter={this.renderFooter}
/>
</View>
</>
);
Here is the getData function:
getData = () => {
if(this.state.isLoading){
return;
}
this.setState({
isLoading: true
});
const url = 'some url?offset=' + this.state.data.length;
fetch(url).then((response) => response.json())
.then((responseJson) => {
this.setState({
data: this.state.data.concat(responseJson.posts),
dataProvider: this.state.dataProvider.cloneWithRows(
this.state.data.concat(responseJson.posts)
),
})
})
.catch((error) => {
console.error(error);
}).finally(() => {
this.setState({
isLoading: false,
})
})
}
Here's renderItem function:
renderItem = (type, item ) => (
<ListItem
containerStyle={{height: 120}}
title={item.title}
subtitle={item.author.name}
leftAvatar={avatar}
bottomDivider
/>
);
And here is renderFooter function:
renderFooter = () => {
return !this.isLoading
? <ActivityIndicator
style={{ marginVertical: 10 }}
size='large'
color='#0A80FE'
/>
: <View style={{ height: 60 }}>
<Text style={{color: '#ccc', textAlign: 'center', paddingVertical: 10,}}> You've reached at the end of the posts.</Text>
</View>;
};
renderFooter always sets to loading even if I reached at the end of the posts resulting in an unending activity indicator

How to get the index value of FlatList in the header using React-native

I need to get the index value of the FlatList used in header of a React native component.
Below is the code I used.I need the parameter rowItem in onPressAction function which is returned as undefined
constructor(props) {
super(props);
this.state = {
selectedItem: '',
headerData: [
{ image: require('common/assets/images/headers/homeicon.png') },
{ image: require('common/assets/images/headers/CustomerDetails2.png') }
]
}
}
componentDidMount() {
// Event Listener for orientation changes
Dimensions.addEventListener('change', () => {
this.setState({
orientation: isPortrait() ? 'portrait' : 'landscape'
});
});
this.props.navigation.setParams({
headerData: this.state.headerData,
selectedItem: this.state.selectedItem,
onPressAction: (item) => this.onPressAction()
});
}
onPressAction = (rowItem) => {
alert(rowItem);
}
static navigationOptions = ({ navigation }) => {
return {
headerTransparent: true,
headerLeft: (
<View style={{ flex: 1, flexDirection: 'row' }} >
<FlatList
horizontal={true}
extraData={navigation.getParam('selectedItem')}
data={navigation.getParam('headerData')}
renderItem={({ item, index }) => (
<TouchableOpacity onPress={navigation.getParam('onPressAction')} >
<Image style={styles.centerIcon} resizeMode='contain' source={item.image}></Image>
</TouchableOpacity>
)}
keyExtractor={(item, index) => index.toString()}
/>
</View >
),
headerTintColor: 'transparent',
};
};
Could anyone please help me
Insert ID into headerData and use it as index value.
headerData: [
{ id: 0 , image: require('common/assets/images/headers/homeicon.png') },
{ id: 1 , image: require('common/assets/images/headers/CustomerDetails2.png') }
]
...
}
renderItem={({ item, index }) => (
<TouchableOpacity onPress={() => alert(navigation.getParam('onPressAction'))} >
<Image style={styles.centerIcon} resizeMode='contain' source={item.image}></Image>
</TouchableOpacity>
)}

React Native Trying to search for users, refreshing every time the user types

I'm trying to make an auto-refreshing flatlist every time the user types something, like Instagram’s search does.
The compiler keeps complaining about a missing variable called search.
import React, { Component } from "react";
import { View, Text, FlatList, ActivityIndicator } from "react-native";
import { List, ListItem, SearchBar } from "react-native-elements";
export default class Home extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
data: [],
page: 1,
error: null,
search: '',
};
}
componentDidMount() {
this.makeRemoteRequest();
}
makeRemoteRequest = () => {
const { page, search } = this.state;
const url = `https://pacific-basin-57759.herokuapp.com/api/account/users?page=${page}&search=${search}`;
this.setState({ loading: true });
fetch(url)
.then(res => res.json())
.then(res => {
this.setState({
data: page === 1 ? res.results : [...this.state.data, ...res.results],
error: res.error || null,
loading: false,
search: this.state.search
})
})
.catch(error => {
this.setState({ error, loading: false });
});
};
handleLoadMore = () => {
this.setState(
{
page: this.state.page + 1
},
() => {
this.makeRemoteRequest();
}
);
};
handleSearch = () => {
this.setState(
{
search: this.state.search
},
() => {
this.makeRemoteRequest();
}
);
}
renderSeparator = () => {
return (
<View
style={{
height: 1,
width: "86%",
backgroundColor: "#CED0CE",
marginLeft: "14%"
}}
/>
);
};
renderHeader = () => {
return <SearchBar placeholder="Type Here..." lightTheme round onChangeText={(text) => this.setState({search:text})} />;
};
renderFooter = () => {
if (!this.state.loading) return null;
return (
<View
style={{
paddingVertical: 20,
borderTopWidth: 1,
borderColor: "#CED0CE"
}}
>
<ActivityIndicator animating size="large" />
</View>
);
};
render() {
return (
<List containerStyle={{ borderTopWidth: 0, borderBottomWidth: 0 }}>
<FlatList
data={this.state.data}
renderItem={({ item }) => (
<ListItem
//roundAvatar
title={`${item.first_name} ${item.last_name}`}
subtitle={item.username}
//avatar={{ uri: item.picture.thumbnail }}
containerStyle={{ borderBottomWidth: 0 }}
/>
)}
keyExtractor={item => item.id}
ItemSeparatorComponent={this.renderSeparator}
ListHeaderComponent={this.renderHeader}
ListFooterComponent={this.renderFooter}
onEndReached={this.handleLoadMore}
onEndReachedThreshold={0.5}
/>
</List>
);
}
}`
I've looked at the Fetch API documentation at MDN and it doesn't really give any useful info (it's all over the place).