Delete data from API(jsonplaceholder) on ReactNative - reactjs

I’m trying to delete user from jsonplaceholder, because I want to delete item with helping click>
/This is official docs/
Delete a resource
fetch('https://jsonplaceholder.typicode.com/posts/1', {
method: 'DELETE'
})
Important: the resource will not be really deleted on the server but it will be faked as if.
/My code/
export default function App() {
const [users, setUsers] = useState();
const pressHandler = (id) => {
fetch(`https://jsonplaceholder.typicode.com/users/${id}`, {
method: 'DELETE'
})
.then(() => {
// Issue GET request after item deleted to get updated list
// that excludes user of id
return fetch(`https://jsonplaceholder.typicode.com/users`)
})
.then(res => res.json())
.then(res => {
setUsers(res);
})
}
/* request API to json.placeholder to get users */
useEffect(() => {
fetch('https://jsonplaceholder.typicode.com/users')
.then(res => res.json())
.then(res => {
setUsers(res);
})
})
I’m trying in another way
export default function App() {
const [users, setUsers] = useState();
const pressHandler = (id) => {
setUsers((prevUsers)=>{
return prevUsers.filter(users => users.id != id)
})
}
}
but it want to remove((
this is my App component
return (
<View style={styles.container}>
<Header />
<View style={styles.content}>
{/* to form */}
<View style={styles.list}>
<FlatList
keyExtractor={item => item.id.toString()}
data={users}
renderItem={({item}) => (
<UserItem item={item} pressHandler={pressHandler}/>
)}
/>
</View>
</View>
</View>
and UserItem component
export default function UserItem({ item, pressHandler }){
return (
<View style={styles.item}>
<TouchableOpacity onPress={() => pressHandler(item.id)}>
<Text style={styles.main}>Employee: {item.name}</Text>
<Text style={styles.company}>Company: {item.company.name}</Text>
<Text style={styles.rest}>City: {item.address.city}, street: {item.address.street}</Text>
<Text style={styles.rest}>email: {item.email}</Text>
</TouchableOpacity>
</View>
)
}

Related

I show the error is " undefined is not a function," whenever i call a one function to another from same class in react-native

i am using a class component and i declared multiple function in same class and try to call one function to another but they show me an error like undefined is not a function
My coding structure is like
class UserList extends Component {
constructor(props) {
super(props);
this.state = {
user_data:[],
};
}
componentDidMount() {
//some other code
}
logOut=(ext_id)=>
{
//logout code
}
UserItem (props,{MainScreen}){
const navigation = useNavigation();
const [name, setName] = useState();
const [image_name, setImg] = useState();
fetch('https://example.com/acc_data.php', {
method: 'POST',
mode: 'no-cors',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
'user_id': props.one,
'key':props.three,
'api_key':`********`
})
}).then((response) => response.json())
.then((json) => {
console.log(json);
setName(json.business_name);
setImg(json.logo);
}).catch((err) => { console.log(err); });
return(
<TouchableRipple
onPress={() => {navigation.navigate('MainScreen',{one:props.one,two:props.two,three:props.three})}}
rippleColor="rgba(0, 0, 0, .1)"
centered={true}
borderless={true}
style={styles.ripple}
>
<Card style={{marginHorizontal:20, marginVertical:10, padding:8, flexDirection:'row'}}>
<View style={{flexDirection:'row'}}>
<Image
style={{height:80,width:80,borderRadius:8}}
source={{
uri:`https://tridevmart.com/web_app/shop_logo/${image_name}`
}} />
<View style={{flex:1}}>
<Text numberOfLines = {1} style={{fontSize:24,margin:10}}>{name}</Text>
<View style={{flexDirection:'row',justifyContent:'space-between'}}>
<Text numberOfLines={5} style={{fontSize:16,marginHorizontal:10,flex:1,color:`#ccc`}}>Income : 2654</Text>
<Button icon="logout" mode="contained" mode="text" onPress={() => this.logOut(props.ext)}>Logout</Button>
</View>
</View>
</View>
</Card>
</TouchableRipple>
);
}
list = () => {
return this.state.user_data.map((element) => {
return (
<this.UserItem key={element.ext_id} ext={element.ext_id} one={element.one} two={element.two} three={element.three}/>
);
});
};
render(){
return(
<SafeAreaView style={{ flex: 1 }}>
<View style={styles.mainBox}>
{this.list()}
<Button mode="contained" style={styles.inputButton} onPress={() => this.props.navigation.navigate('LoginScreen')}>+ Add More Account</Button>
</View>
</SafeAreaView>
);
}
}
in this coding i am trying to call logOut() inside a onPress attribute of UserItem component
So plese hel me to find out a exect solution. i am new in react native so please help me to how can i solve this and how can i proceed my futher work

TypeError: undefined is not an object (evaluating 'data[imageKey].urls')

The error says undefined is not an object (evaluating.data [imageKey] .urls)
I'm not passing the URL correctly.
TypeError: undefined is not an object (evaluating 'data[imageKey].urls')
node_modules\react-native\Libraries\LogBox\LogBox.js:148:8 in registerError
node_modules\react-native\Libraries\LogBox\LogBox.js:59:8 in errorImpl
node_modules\react-native\Libraries\LogBox\LogBox.js:33:4 in console.error
const ImageListWithHooks = (props) => {
useEffect(() => {
fetch('https://api.unsplash.com/photos/?client_id=cf49c08b444ff4cb9e4d126b7e9f7513ba1ee58de7906e4360afc1a33d1bf4c0')
.then((response) => response.json())
.then((json) => setData(json))
.catch((error) => console.log(error))
.finally(() => setLoading(false));
}, []);
const [loading, setLoading] = useState()
const [data, setData] = useState([]);
const [modalVisible, setModalVisible] = useState(false)
const [modalImage, setModalImage] = useState(props.imgsource)
const setModal = (visible, imageKey) => {
setModalImage({ modalImage: visible ? data[imageKey].urls.raw : null })
setModalVisible({ modalVisible: visible })
}
let images = data.map((val, key) => {
return <TouchableWithoutFeedback key={key}
onPress={() => { setModal(key) }}>
<View style={styles.imagewrap}>
<ImageElement
author={{ url: val.user.profile_image.small }} // фото автора
imgsource={{ url: val.urls.small }} // работа автора
authorNameProp={val.user.name} // имя автора
></ImageElement>
</View>
</TouchableWithoutFeedback>
});
return (
<ScrollView>
<View style={styles.container}>
<Modal
style={styles.modal}
animationType={'fade'}
transparent={true}
visible={modalVisible}
onRequestClose={() => { }}
>
<View style={styles.modal}>
<Text style={styles.text}
onPress={() => { setModal }}>Close</Text>
<View>
<Text style={styles.spinner}>Loading... <ActivityIndicator /></Text>
</View>
<ImageElement
imgsource={{ url: modalImage }}
></ImageElement>
</View>
</Modal>
{images}
</View>
</ScrollView>
);
}
export default ImageListWithHooks;
try this:
const setModal = useCallback((visible, imageKey) => {
setModalImage({ modalImage: visible ? data[imageKey].urls.raw : null })
setModalVisible({ modalVisible: visible })
}, [data])

FlatList does not rerender even if state assigned to extraData changes

I am building a Instagram clone backed by firebase and redux. I have a Profile screen in which i render the posts that the user has made. The problem with this is the posts does not get updated, I was using FlatList component and found that we need to use a extraData prop.
This is my Profile.tsx (Profile screen) :
import React, { useState, useEffect } from "react";
import { View, Text, StyleSheet, Image, FlatList, Alert } from "react-native";
import db, { auth } from "../../firebase";
import { Avatar, Button, ActivityIndicator, Colors } from "react-native-paper";
import Navbar from "../shared/Navbar";
import { connect } from "react-redux";
import { FontAwesome5 } from "#expo/vector-icons";
const Profile = ({
navigation,
posts,
route,
reduxFollowing,
currentUser,
}: any) => {
const [user, setUser] = useState<any>(null);
const [userPosts, setUserPosts] = useState<any>([]);
const [loading, setLoading] = useState<boolean>(true);
const [following, setFollowing] = useState<boolean>(false);
const [refresh, setRefresh] = useState<boolean>(false);
useEffect(() => {
if (route.params.uid === auth.currentUser?.uid) {
setUser(auth.currentUser);
setUserPosts(posts);
setLoading(false);
} else {
db.collection("users")
.doc(route.params?.uid)
.get()
.then((snapshot) => {
setLoading(false);
if (snapshot.exists) {
setUser(snapshot.data());
} else {
console.log("does not exist");
}
});
db.collection("posts")
.doc(route.params.uid)
.collection("userPosts")
.orderBy("creation", "desc")
.onSnapshot((snapshot) => {
let posts = snapshot.docs.map((doc) => {
const data = doc.data();
const id = doc.id;
return { ...data, id };
});
setUserPosts(posts);
setRefresh(!refresh);
});
if (reduxFollowing.indexOf(route.params.uid) > -1) {
setFollowing(true);
} else {
setFollowing(false);
}
}
}, [route.params.uid, reduxFollowing]);
useEffect(() => {
setRefresh(!refresh);
}, [posts]);
const onFollow = () => {
db.collection("following")
.doc(auth.currentUser?.uid)
.collection("userFollowing")
.doc(route.params.uid)
.set({})
.then(() => setFollowing(true))
.catch((err) =>
Alert.alert("Opps!, could not Login", err.message, [{ text: "Ok" }])
);
};
const onUnfollow = () => {
db.collection("following")
.doc(auth.currentUser?.uid)
.collection("userFollowing")
.doc(route.params.uid)
.delete()
.then(() => setFollowing(false))
.catch((err) =>
Alert.alert("Opps!, could not Login", err.message, [{ text: "Ok" }])
);
};
if (loading) {
return (
<View style={styles.loading}>
<ActivityIndicator size={60} color={Colors.blue500} />
</View>
);
}
console.log(posts);
const TwoBtn = () => (
<>
{following ? (
<Button
style={styles.btn}
uppercase={false}
mode="outlined"
color={Colors.green500}
onPress={onUnfollow}
>
Following
</Button>
) : (
<Button
style={styles.btn}
uppercase={false}
mode="outlined"
color="black"
onPress={onFollow}
>
Follow
</Button>
)}
<Button
style={styles.btn}
uppercase={false}
mode="outlined"
color="black"
onPress={() => navigation.navigate("Chat")}
>
Chat
</Button>
</>
);
const OneBtn = () => (
<Button
style={styles.btn2}
uppercase={false}
mode="outlined"
color="black"
onPress={() => navigation.navigate("EditProfile", { user })}
>
Edit Profile
</Button>
);
const imgSrc = user?.photoURL;
console.log(refresh);
return (
<View style={styles.container}>
<Navbar
navigation={navigation}
title={auth.currentUser?.displayName || currentUser.name}
/>
<View style={styles.topContainer}>
{imgSrc ? (
<Avatar.Image source={{ uri: imgSrc }} />
) : (
<FontAwesome5 name="user-circle" size={60} color="black" />
)}
<View style={styles.topRightCont}>
<Text style={styles.label}>
Name :{" "}
<Text style={styles.text}>{user?.displayName || user?.name}</Text>
</Text>
<Text style={styles.label}>
Email : <Text style={styles.text}>{user?.email}</Text>
</Text>
</View>
</View>
{route.params.uid === auth.currentUser?.uid ? (
<View style={styles.btnCont}>
<OneBtn />
</View>
) : (
<View style={styles.btnCont}>
<TwoBtn />
</View>
)}
<View style={styles.galleryCont}>
<FlatList
keyExtractor={(item) => item?.id}
numColumns={3}
horizontal={false}
data={userPosts}
extraData={refresh}
renderItem={({ item }) => (
<Image style={styles.image} source={{ uri: item?.downloadURL }} />
)}
/>
</View>
</View>
);
};
const styles = StyleSheet.create({
//styles
});
const mapStateToProps = (store: any) => ({
currentUser: store.userState.currentUser,
posts: store.userState.posts,
reduxFollowing: store.userState.following,
});
export default connect(mapStateToProps, null)(Profile);
Here I am using the refresh state that changes whenever the posts changes, but the flatlist does not get updated.
NOTE :
I can see in the console that posts are being updated and the refresh state too, so I expect that the flatlist gets re-rendered with new posts but that does not happen.
I have gone through all the other SO questions but couldn't find them useful because all of them are in class components.

React native looping through array

I have array of colors that is being rendered with a flatlist. The flatlist data is coming from remote url. The colors are hardcoded in the app. The issue is that I am having is that the json data that is coming from api contain more rows of data than the colors I have in a array which result in only 5 items showing. Can someone help me with allowing the colors to repeat (make the index of colors repeat over and over)
componentDidMount() {
fetch('https://reactnative.dev/movies.json')
.then((response) => response.json())
.then((json) => {
this.setState({data: json.movies});
})
.catch((error) => console.error(error))
.finally(() => {
this.setState({isLoading: false});
});
}
render() {
const Colors = ['#1abc9c', '#9b59b6', '#7b59f9'];
const {data, isLoading} = this.state;
return (
<SafeAreaView style={{flex: 1, padding: 24}}>
{isLoading ? (
<ActivityIndicator />
) : (
<FlatGrid
itemDimension={130}
data={data}
style={styles.gridView}
keyExtractor={({id}, index) => id}
// staticDimension={300}
// fixed
spacing={10}
renderItem={({item, index}) => (
<View
style={[
styles.itemContainer,
{backgroundColor: Colors[index]},
]}>
<Text style={{color: 'white'}}>{item.title}</Text>
<Text style={{color: 'white'}}>{item.releaseYear}</Text>
</View>
)}
/>
)}
</SafeAreaView>
Simply use a modulo: {backgroundColor: Colors[index % Colors.length]}
const Colors = ["#1abc9c", "#9b59b6", "#7b59f9"];
for (let i = 0; i < 10; i++) {
console.log(Colors[i % Colors.length]);
}

Impossible to display the data after a get request react native

i'm trying to display information of a restaurant in my react-native app after i get it by a get request from my database. I don't have problem getting the data, it's the display the problem.
Inside my component RestaurantDetailScreen :
componentDidMount() {
this.getRestaurantInfo()
}
getRestaurantInfo = async () => {
try {
let res = await axios({
method: 'get',
url: `${environment.apiDevUrl}/restaurant/${this.state.restaurantId}`,
})
this.setState({
restaurantInfo: res.data,
})
console.log(this.state.restaurantInfo.restaurant.nom);
} catch (error) {
console.error(error)
}
}
The console log display my state with correct data from my backend, but when I try to render it inside my Flatlist there is nothing to display:
<ScrollView style={styles.container}>
{/* <Text>{this.state.restaurantInfo.restaurant.nom}</Text> */}
<FlatList
data={this.state.restaurantInfo}
renderItem={this.renderRestaurantInfo}
keyExtractor={item => `${item.restaurant.id}`}
/>
<SectionList
sections={productData}
ItemSeparatorComponent={this.renderSeparator}
renderItem={this.renderRestaurantDetail}
renderSectionHeader={({section: {header}}) => (
<Text style={styles.sectionHeader}>{header}</Text>
)}
keyExtractor={(item, index) => `${item.id}` + index}
ref={ref => (this.sectionListRef = ref)}
getItemLayout={this.getItemLayout}
/>
</ScrollView>
So i've tried to simply display the name of a restaurant inside a Text component like in the getRestaurantInfo() method but it will return a undefined if i don't remove it.
The render method renderRestaurantInfo() :
renderRestaurantInfo = ({item}) => (
<View style={styles.containerRestaurantInfo}>
{console.log('item : ', item)}
<ItemRestaurantInfo
// image={item.restaurant.image}
title={item.restaurant.nom}
description={item.restaurant.description}
categories={item.restaurant.categorie}
adress={item.restaurant.adresse.rue1}
scheduleBeginning={item.restaurant.horaires.crenaux.hDebut}
scheduleEnd={item.restaurant.horaires.crenaux.hFin}
/>
</View>
)
And finally the ItemRestaurantInfo component :
ItemRestaurantInfo = ({
image,
title,
categories,
adress,
description,
scheduleBeginning,
scheduleEnd,
}) => {
return (
<View>
{/* <Image source={image} style={styles.topImage} /> */}
<View style={{padding: 15}}>
<Text style={styles.restaurantTitle}>{title}</Text>
<Text style={styles.restaurantInfoText}>{`${categories}`}</Text>
<View style={styles.viewInRow}>
<Image
style={{margin: 5}}
source={require('../../assets/icons/map-pin.png')}
/>
<Text style={styles.restaurantInfoText}>{adress}</Text>
</View>
<Text style={styles.restaurantInfoText}>{description}</Text>
<View style={styles.viewInRow}>
<Image
style={{margin: 5}}
source={require('../../assets/icons/calendar.png')}
/>
<Text style={styles.restaurantInfoText}>{scheduleBeginning} - {scheduleEnd}</Text>
</View>
</View>
</View>
)
}
You forget to pass item in your FlatList renderItem:
<FlatList
data={this.state.restaurantInfo}
renderItem={({item}) => this.renderRestaurantInfo(item)}
...
/>
You could also return a Component instead of method:
const RenderItems = ({ title }) => {
return (
<View>
<Text>{title}</Text>
</View>
);
}
...
// Pass the component to your FlatList
<FlatList
data={YOURDATA}
renderItem={({ item }) => <RenderItems title={item.title} />}
...
/>
And same thing goes for your SectionList
Edit: Working condeSandbox example with data fetch.
Ok I have finally find the solution, it was because my array restaurantInfo in the state was transform in an object when I use setState in the call of my backend... so inside the render method of the flatList there was no data.
OLD CODE
getRestaurantInfo = async () => {
try {
let res = await axios({
method: 'get',
url: `${environment.apiDevUrl}/restaurant/${this.state.restaurantId}`,
})
this.setState({
restaurantInfo: res.data,
})
} catch (error) {
console.error(error)
}
}
NEW CODE
getRestaurantInfo = async () => {
try {
let res = await axios({
method: 'get',
url: `${environment.apiDevUrl}/restaurant/${this.state.restaurantId}`,
})
let newArray = [...this.state.restaurantInfo];
newArray[0] = res.data
this.setState({
restaurantInfo: newArray,
})
console.log('state dans getResturantinfo:',this.state.restaurantInfo);
} catch (error) {
console.error(error)
}
}
With this syntax it force react to keep an array. And finally it was not necessery to use this syntax : renderItem={({item}) => this.renderRestaurantInfo(item)}
In my code I keep it like this :
<FlatList
data={this.state.restaurantInfo}
renderItem={this.renderRestaurantInfo}
keyExtractor={item => `${item.restaurant.id}`}
/>

Resources