SetState doesn't seem to update - javascript

I'm working on a very simple react-native app where I type the name of an artist in a searchbox, retrieve a list of artists from the spotify API and I display this list in FlatList component.
I manage to get the list of artists and I want to save it in the local state so that I pass it to the FlatList component.
The list object looks like this : [{...}, {...}, {...}, {...}]
But it doesn't seem to work and I think that my state is not updating and I don't know what I'm doing wrong.
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
FlatList,
StatusBar,
TextInput,
} from 'react-native';
import colors from './utils/colors';
import { List, ListItem, SearchBar } from 'react-native-elements';
import { searchArtist } from './utils/fetcher';
import { debounce } from 'lodash';
export default class spotilist extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
data: [],
query: '',
artists: [],
error: null,
refreshing: false,
};
}
render() {
return (
<View style={ styles.container }>
<StatusBar barStyle="light-content" />
<TextInput style={ styles.searchBox }
value={this.state.value}
onChangeText={ this.makeQuery }
/>
<List>
<FlatList
data={this.state.artists}
//renderItem={({item}) => <Text>{item.name}</Text>}
/>
</List>
// {
// this.state.artists.map(artist => {
// return (
// <Text key={artist.id}>{artist.name}</Text>
// )
// })
// }
</View>
);
}
makeQuery = debounce(query => {
searchArtist(query)
.then((artists) => {
console.log(artists); // I have the list
this.setState({
artists: this.state.artists,
});
})
.catch((error) => {
throw error;
});
}, 400);
}
Thank you for your help.
UPDATE
I also tried using this without success :
<List>
<FlatList
data={this.state.artists}
renderItem={({ item }) => (
<ListItem
roundAvatar
title={item.name}
avatar={{ uri: item.images[0].url }}
/>
)}
/>
</List>

In the makeQuery function you need to set the response from the server like..
makeQuery = debounce(query => {
searchArtist(query)
.then((artists) => {
console.log(artists); // I have the list
this.setState({
artists: artists, //Here is the change
});
})
.catch((error) => {
throw error;
});
}, 400);

Related

Flat list is not rendering

I'm trying to display a flat list (values form json placeholder) filterable with a search bar and it's not rendering for some reason. The values are not visible. Thanks!
The flat list code:
import React, { Component } from "react";
import { View, Text, FlatList, Button } from "react-native";
import { ListItem, SearchBar } from "react-native-elements";
class FlatListDemo extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
data: [],
temp: [],
error: null,
search: null
};
}
componentDidMount() {
this.getData();
}
getData = async () => {
const url = `https://jsonplaceholder.typicode.com/users`;
this.setState({ loading: true });
try {
const response = await fetch(url);
const json = await response.json();
this.setResult(json);
} catch (e) {
this.setState({ error: 'Error Loading content', loading: false });
}
};
setResult = (res) => {
this.setState({
data: [...this.state.data, ...res],
temp: [...this.state.temp, ...res],
error: res.error || null,
loading: false
});
}
renderHeader = () => {
return <SearchBar placeholder="Search Here..."
lightTheme round editable={true}
value={this.state.search}
onChangeText={this.updateSearch} />;
};
updateSearch = search => {
this.setState({ search }, () => {
if ('' == search) {
this.setState({
data: [...this.state.temp]
});
return;
}
this.state.data = this.state.temp.filter(function(item){
return item.name.includes(search);
}).map(function({id, name, email}){
return {id, name, email};
});
});
};
render() {
return (
this.state.error != null ?
<View style={{flexDirection: 'column',justifyContent: 'center', alignItems: 'center' }}>
<Text>{this.state.error}</Text>
<Button onPress={
() => {
this.getData();
}
} title="Reload" />
</View> :
<FlatList
ListHeaderComponent={this.renderHeader}
data={this.state.data}
keyExtractor={item => item.email}
renderItem={({ item }) => (
<ListItem
roundAvatar
title={`${item.name}`}
subtitle={item.email}
/>
)}
/>
);
}
}
export default FlatListDemo;
Importing this list to:
import React, {useState, useEffect} from 'react'
import { Text, View, StyleSheet, StatusBar, SafeAreaView } from "react-native"
import "firebase/auth";
import 'react-native-gesture-handler';
import "firebase/auth";
import 'firebase/compat/auth';
import 'firebase/compat/firestore';
import FlatListDemo from './FlatListDemo';
const Home: () => React$Node = () => {
return(
<>
<StatusBar barStyle="dark-content"/>
<SafeAreaView style={{flex: 1}}>
<FlatListDemo/>
</SafeAreaView>
</>
);
};
export default Home;
This is what it looks like (values should be there). Using Expo on Android:
photo1
Thanks! I appreciate the help!
It seems to me that you are using a ListElement as it is defined in version 1.2.0 of react-native-elements but the actual version that you are using is > 1.2.0.
You are implementing it similar to the documentation of react-native-elements 1.2.0.
However, the definition of ListItem has changed in newer version. In the newest version, the ListItem component is just a simple view wrapper. Hence, it needs to contain children in order to display the information that you want.
In your case this could be implemented as follows (I did not know what roundAvatar is doing).
renderItem={({ item }) => (
<ListItem>
<ListItem.Content>
<ListItem.Title>{`${item.name}`}</ListItem.Title>
<ListItem.Subtitle>{item.email}</ListItem.Subtitle>
</ListItem.Content>
</ListItem>
Check the documentation of the newest version for the exact features that you want to use.

Not able to delete items from flatList In react-native from Api,ApiCard is another Component where the required data items are coming had a del buttn

It's not deleting anything and delete action isn't working
import React, {Component} from 'react';
import {
StyleSheet,
View,
FlatList,
Text,
TouchableOpacity,
SafeAreaView,
Button,
} from 'react-native';
import ApiCard from './ApiCard';
export default class ApiList extends Component {
constructor(props) {
super(props);
this.state = {
loading: true,
dataSource: [],
};
}
static navigationOptions = {
title: 'List of countries',
};
componentDidMount() {
fetch('https://restcountries.eu/rest/v2/all')
.then(response => response.json())
.then(responseJson => {
this.setState({
loading: false,
dataSource: responseJson,
});
})
.catch(error => console.log(error));
}
render() {
const {dataSource} = this.state;
const {navigation} = this.props;
return (
<SafeAreaView style={styles.container}>
<FlatList
data={dataSource}
keyExtractor={item => item.name}
renderItem={data => (
<ApiCard {...data.item} navigation={navigation} />
)}
/>
</SafeAreaView>
);
}
}
The below component is for data rendering as props:
import React from 'react';
import {TouchableOpacity, Text, StyleSheet, Button} from 'react-native';
const ApiCard = ({name, navigation, alpha2Code, population, capital}) => {
return (
<TouchableOpacity
style={styles.country}
onPress={() =>
navigation.push('CountryName', {
name,
alpha2Code,
population,
capital,
})
}>
<Text>{name}</Text>
<Text>{alpha2Code}</Text>
<Button title="del" />
Here I need a del button action :
</TouchableOpacity>
);
};
export default ApiCard;

How to Show Activity Indicator Until data if Fetched from Firebase Using Redux

I am Using FireBase as a Database for fetching data in a react-native app using Redux. I want to Show an Activity Indicator until the data is been fetched.
Here is my code Redux :
export function getHome() {
const request = axios({
method: "GET",
url: `${FIREBASEURL}/home.json`
})
.then(response => {
const articles = [];
for (let key in response.data) {
articles.push({
...response.data[key],
id: key
});
}
return articles;
})
.catch(e => {
return false;
});
return {
type: GET_HOME,
payload: request
};
}
Here is my React Native code where data will be shown:
import React, { Component } from "react";
import {
StyleSheet,
View,
Text,
ScrollView,
ActivityIndicator,
TouchableWithoutFeedback,
Image
} from "react-native";
import { connect } from "react-redux";
import { getHome } from "../store/actions/home_actions";
import DemoScreen from "./rn-sound/demo";
class HomeScreen extends Component {
componentDidMount() {
this.props.dispatch(getHome());
}
renderArticle = imgs =>
imgs.articles
? imgs.articles.map((item, i) => (
<TouchableWithoutFeedback
onPress={() => this.props.navigation.navigate(`${item.navigate}`)}
key={i}
>
<View>
<View>
<Image
style={{
height: 220,
width: "100%",
justifyContent: "space-around"
}}
source={{ uri: `${item.image}` }}
resizeMode="cover"
/>
</View>
<View>
<Text >{item.name}</Text>
</View>
<View>
<Text }>{item.tagline}</Text>
</View>
</View>
</TouchableWithoutFeedback>
))
: null;
render() {
return (
<ScrollView}>
{this.renderArticle(this.props.Home)}
</ScrollView>
);
}
}
how to show Activity Indiactor Untill my data from firebase is been Fetched
You can use loading variable in state. You have set false it before fetch command after that set to true. You can see below sample.
constructor(props) {
super(props);
this.state = {
loading: false
};
}
componentDidMount = () => {
this.setState({
loading: true
})
this.props.dispatch(getHome()).then(response=>{
this.setState({
loading: false
})
})
}
render() {
return (
<ScrollView}>
{this.state.loading == false ? (
<View>
{this.renderArticle(this.props.Home)}
</View>
) : (
<ActivityIndicator size="large" />
)}
</ScrollView>
);
}

How To Get Props in another Screen in react navigation?

I have an issue with react-navigation in passing the props to another screen,
I need to pass some props to Detail screen when the user presses one of the List Places I need to push screen with some details about the place like a Name of place and Image of place,
Errors :
this is my Code
Reducer
import { ADD_PLACE, DELETE_PLACE } from "../actions/actionTypes";
const initialState = {
places: []
};
import placeImage from "../../assets/img.jpg";
const reducer = (state = initialState, action) => {
switch (action.type) {
case ADD_PLACE:
return {
...state,
places: state.places.concat({
key: Math.random(),
name: action.placeName,
// image: placeImage,
image: {
uri:
"https://images.unsplash.com/photo-1530009078773-9bf8a2f270c6?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=750&q=80"
}
})
};
case DELETE_PLACE:
return {
...state,
places: state.places.filter(place => {
return place.key !== state.selectedPlace.key;
})
};
default:
return state;
}
};
export default reducer;
Place List Component
import React from "react";
import { FlatList, StyleSheet, ScrollView } from "react-native";
import ListItem from "../ListItem/ListItem";
const PlaceList = props => {
return (
<FlatList
style={styles.listContainer}
data={props.places}
renderItem={info => (
<ListItem
placeName={info.item.name}
placeImage={info.item.image}
onItemPressed={() => props.onItemSelected(info.item.key)}
/>
)}
keyExtractor={index => String(index)}
/>
);
};
export default PlaceList;
Find Place Screen
import React, { Component } from "react";
import { View, Text } from "react-native";
import { connect } from "react-redux";
import { StackActions } from "react-navigation";
import PlaceList from "../../Components/PlaceList/PlaceList";
class FindPlaceScreen extends Component {
constructor() {
super();
}
itemSelectedHandler = key => {
const selPlace = this.props.places.find(place => {
return place.key === key;
});
this.props.navigation.push("PlaceDetail", {
selectedPlace: selPlace,
name: selPlace.name,
image: selPlace.image
});
};
render() {
return (
<View>
<PlaceList
places={this.props.places}
onItemSelected={this.itemSelectedHandler}
/>
</View>
);
}
}
const mapStateToProps = state => {
return {
places: state.places.places
};
};
export default connect(mapStateToProps)(FindPlaceScreen);
Place Details Screen
import React, { Component } from "react";
import { View, Text, Image, TouchableOpacity, StyleSheet } from "react-native";
import Icon from "react-native-vector-icons/Ionicons";
class PlaceDetail extends Component {
constructor(props) {
super(props);
}
render() {
return (
<View style={styles.modalContainer}>
<View>
<Image
source={this.props.navigation.state.params.image}
style={styles.placeImage}
/>
<Text style={styles.placeName}>
{this.props.navigation.state.params.namePlace}
</Text>
</View>
<View>
<TouchableOpacity onPress={props.onItemDeleted}>
<View style={styles.deleteButton}>
<Icon size={30} name="ios-trash" color="red" />
</View>
</TouchableOpacity>
<TouchableOpacity onPress={props.onModalClosed}>
<View style={styles.deleteButton}>
<Icon size={30} name="ios-close" color="red" />
</View>
</TouchableOpacity>
</View>
</View>
);
}
}
export default PlaceDetail;
You need to use react-native-navigation v2 for the find place screen
itemSelectedHandler = key => {
const selPlace = this.props.places.find(place => {
return place.key === key;
});
Navigation.push(this.props.componentId, {
component: {
name: 'PlaceDetail',
options: {
topBar: {
title: {
text: selPlace.name
}
}
},
passProps: {
selectedPlace: selPlace
}
}
});
};
make sure you import { Navigation } from "react-native-navigation";
Your PlaceDetail has some error
<TouchableOpacity onPress={props.onItemDeleted}>
<TouchableOpacity onPress={props.onModalClosed}>
Change props to this.props
<TouchableOpacity onPress={this.props.onItemDeleted}>
<TouchableOpacity onPress={this.props.onModalClosed}>
But I don't see onItemDeleted and onModalClosed anywhere, don't forget to pass those to PlaceDetail via props as well :)

Trouble getting function from different component

I'm new to react native. I am trying to get a 'Key' from a different component. I mean I am trying to call a function from a different component, as a parent component. But, I'm totally jumbled with all these reference calls and all. Please suggest to me how to call a function from a different component.
// AddScreen.js
import React, { Component } from 'react';
import { AppRegistry, AsyncStorage, View, Text, Button, TextInput, StyleSheet, Image, TouchableHighlight, Linking } from 'react-native';
import styles from '../components/styles';
import { createStackNavigator } from 'react-navigation';
import History from '../components/History';
export default class AddScreen extends Component {
constructor(props) {
super(props);
this.state = {
myKey: '',
}
}
getKey = async () => {
try {
const value = await AsyncStorage.getItem('#MySuperStore:key');
this.setState({ myKey: value });
} catch (error) {
console.log("Error retrieving data" + error);
}
}
async saveKey(value) {
try {
await AsyncStorage.setItem('#MySuperStore:key', value);
} catch (error) {
console.log("Error saving data" + error);
}
}
componentDidMount() {
this.getKey();
}
render() {
const { navigate } = this.props.navigation;
return (
<View style={styles.MainContainer}>
<View style={styles.Date_input}>
<TextInput
placeholder="Add input"
value={this.state.myKey}
onChangeText={(value) => this.saveKey(value)}
/>
</View>
<View style={styles.getKeytext}>
<Text >
Stored key is = {this.state.myKey}
</Text>
</View>
<View style={styles.Historybutton}>
<Button
onPress={() => navigate('History')}
title="Press Me"
/>
</View>
</View>
)
}
}
//History.js
import React, { Component } from 'react';
import AddScreen from '../components/AddScreen';
import {
AppRegistry,
StyleSheet,
Text,
TextInput,
Button,
View,
AsyncStorage
} from 'react-native';
export default class History extends Component {
constructor(props) {
super(props);
this.state = {
myKey: ''
}
}
render() {call async function synchronously
return (
<View style={styles.container}>
<Button
style={styles.formButton}
onPress={this.onClick}
title="Get Key"
color="#2196f3"
accessibilityLabel="Get Key"
/>
<Text >
Stored key is = {this.state.mykey}
</Text>
</View>
)
}
}
const styles = StyleSheet.create({
container: {
padding: 30,
flex: 1,
backgroundColor: '#F5FCFF',
},
});
I just want to call the getKey function from the History component to get the myKey value on the History component's screen.
Please suggest to me, by taking my components as an example.
You just simply need to pass the key via navigation parameters.
<Button
onPress={() => navigate('History', { key: this.state.myKey })}
title="Press Me"
/>
and in your history component you can do
render() {
const key = this.props.navigation.getParam('key');
return (
// other code
)
}
You can read more about passing parameters here. https://reactnavigation.org/docs/en/params.html

Categories