React native contacts in list works really slow - react-native

I'm trying to add a feature to my app which is add your contacts to your profile. I'm using a package for this but it works slow (in my case 470 contact record I got in my phone).
The package
import Contacts from 'react-native-contacts';
My code
componentDidMount() {
this.getContacts();
}
getContacts() {
PermissionsAndroid.request(PermissionsAndroid.PERMISSIONS.READ_CONTACTS, {
title: 'Contacts',
message: 'This app would like to view your contacts.',
buttonPositive: 'Please accept bare mortal',
})
.then(
Contacts.getAllWithoutPhotos().then(contacts => {
var contactss = [];
contacts.map(contact => {
/// I'm mapping it for showing them in simple list with checkbox
contactss.push({...contact, checked: false});
});
// then sorting for alphabetical order by displayName
contactss.sort(function (a, b) {
if (a.displayName.toLowerCase() < b.displayName.toLowerCase())
return -1;
if (a.displayName.toLowerCase() > b.displayName.toLowerCase())
return 1;
return 0;
});
this.setState(
{contacts: contactss, loaded: true},
() => {
console.log('contacts', this.state.contacts);
},
);
}),
)
.then(contacts => {});
}
That's all code. Is this normal or should I do what?
Thank you.
I'm just trying to handle with this data. Also I'm giving select option to user which account you want, like this.
//function to select contact
checkContc(contc) {
console.log('checkFriend', contc);
let contactsTemp = this.state.contactsTemp.map(el =>
el.recordID == contc.recordID
? {...el, checked: !el.checked}
: {...el},
);
this.setState({contactsTemp}, () => {
console.log('check frined stateD ', this.state);
});
}
// render in scrollview
<ScrollView>
{this.state.contactsTemp?.map((follower, index) => {
return (
<TouchableOpacity
onPress={() => {
this.checkFriend(follower);
}}>
<FriendsComponent
checked={follower.checked}
nameSurname={follower.displayName}
key={index}
/>
</TouchableOpacity>
);
})}
</ScrollView>
result

I made a research and it looks like it is that slow. I'm not sure if the only solution isn't the native one.

Related

Bug at pressable in React Native

im currently developing a log in system .My bug is when i press the pressable button it sends the data to the backend (node server) and recieve a correct status(so the check for the user profile is fine),but it not navigate always to the "Home Page" at first press.The second press make is work but not always with first press,why?
Thanks in advance.
Here are some parts of the code.
Client
//AXIOS request
function getProfile(){
try{
axios.post('http://********/checkData',
{
usernameCheckAXIOS : username,
passwordCheckAXIOS : password,
})
.then(function (response){
setProfile(response.data);
}).catch((error) => {console.log("Log In axios error" + error)})
}
catch(error){
console.log("LogIn try Error" + error);
}
}
{/* Pressable for Sing In */}
<Pressable style = {styles.pressableSignIn} onPress = {() => {getProfile(); if(profile.responseOfProfile == true)
{navigation.navigate('Home')}}}>
<Text style = {styles.signText}>Sign in</Text>
</Pressable>
Node server
//Flag for user response profile
var dataProfile = {
responseOfProfile : false,
dataOfProfile : '',
}
//For data login - Check
app.post("/checkData",(req,res) => {
resultOfData = req.body;
console.log(resultOfData);
database.query(`SELECT id,username,password,image,email from register where username='${resultOfData.usernameCheckAXIOS}' AND password='${resultOfData.passwordCheckAXIOS}'`,(reqQuery,resQuery) => {
if(resQuery != 0){
dataProfile = {
responseOfProfile : true,
dataOfProfile : resQuery[0],
}
res.send(dataProfile);
dataProfile = {
responseOfProfile : false,
dataOfProfile : '',
}
}else{
res.send("false");
}});
})
This part of your code is async (hook state doc)
setProfile(response.data);
You could do it this way:
...
useEffect(() => {
if (profile?.responseOfProfile) {
navigation.navigate('Home')
}
}, [profile])
...
<Pressable style={styles.pressableSignIn} onPress = {() => getProfile())

Encountered two children with the same key - React Native Gifted Chat

The bellow code runs somewhat to what I want. I'm able to get the correct data when i enter the component, but as soon as I send a message, it duplicates the previous messages. I'm quite new to React Native so just learning. Any help or suggestions would be appreciated!
1.) Fetch documents where 'selectedUser (local) == field 'to' in Firebase.
2.) Display chats from the found documents.
3.) Send message to screen and firebase.
4.) Profit.
useEffect(() => {
const q = query(collectionRef, orderBy('createdAt', 'desc'));
const unsubscribe = onSnapshot(q, querySnapshot => {
const id = querySnapshot.docs.map(doc => ({
_id: doc.data()._id,
createdAt: doc.data().createdAt.toDate(),
text: doc.data().text,
user: doc.data().user,
to: doc.data().to
}))
id.forEach((val)=>{
if(val.to == selectedUser[0]){
console.log(val.to)
DATA.push({
_id: val._id,
createdAt: val.createdAt,
text: val.text,
user: val.user,
to: val.to,
}
);
}
})
// console.log(DATA)
setMessages(DATA);
// console.log(Message)
});
return () => unsubscribe();
}, []);
const onSend = useCallback((messages = []) => {
const to = selectedUser.toString();
const { _id, createdAt, text, user } = messages[0]
addDoc(collection(db, 'Chats'), { _id, createdAt, text, user, to });
}, []);
return (
<SafeAreaView style={styles.container}>
<Text style={styles.ChattingWith}>Chatting with: {selectedUser[[0]]}</Text>
<View style={styles.MainFeed}>
<GiftedChat
messages={messages}
showAvatarForEveryMessage={true}
onSend={messages => onSend(messages)}
user={{
_id: auth?.currentUser?.email,
avatar: auth?.currentUser?.photoURL
}}
/>
</View>
</SafeAreaView>
)
}
What Firestore has when 'onSend' function is called:
can you try replacing
id.forEach((val)=>{
if(val.to == selectedUser[0]){
console.log(val.to)
DATA.push({
_id: val._id,
createdAt: val.createdAt,
text: val.text,
user: val.user,
to: val.to,
}
);
}
})
setMessages(DATA);
with
const newData = id.filter((val)=> val.to == selectedUser[0])
setMessages(newData);

React Native Workflow, handle 429 erros and data

im looking for a bit of guideness here, im working on a RN app with redux and everytime i enter a new screen on the app, must likely i have a "callinitialData" function inside my useEffect(), using axios to fetch api data to be dispatch() to the redux state.
Everything works but whenever i jump from screen to screen to fast, sometimes i get a 429 error of to many request, so i just setup the redux-persist hoping that would help reduce the amount of request,in my mind thinking that if my api data is equal to my local data, that request wouldnt be necessary to be made.
However it stays the same so i was thinking what would be the best aproach here, on login try to fetch all the data at once > store it at asyncstorage and redux, and fetch that on each screen ?
how would i be able then, if i fetch all the data on login, receive the new data sets from the api in real time?
App functionality -
Edit Profile (img, pass, email, name)
Data Forms (requeast X, submit data, edit forms)
Chat by contacts / create Group chat
Code Example
const ChatScreen = ({ auth: { user }, getChatContacts, chat: { contacts }, navigation }) => {
useEffect(() => {
getChatContacts();
}, []);
const onChatUser = async (_id, name, roomID) => {
console.log(_id, name, roomID, contacts.payload.clone)
navigation.navigate( "Message", {
_id, name, chatRoomId: roomID, allUsers: contacts.payload.clone
});
}
const renderItem = ({ item , index } ) => {
let userName = "";
item.users.map((users, index) => {
let idToCheck = users.toString() !== user._id.toString() ? users : false;
if (idToCheck) {
let getOneUser = contacts.payload.clone.find(x => x._id === idToCheck);
userName += "" + getOneUser.name + ", ";
}
})
return (<TouchableOpacity key={item._id} onPress={() => onChatUser(item._id, item.name, item.roomID)}>
<View style={styles.chatContainer}>
<FontAwesome name="user-circle-o" size={50} color="#000000"/>
<Text style={styles.chatTitle}>{ ((userName).length > 32) ?
(((userName).substring(0,32-3)) + '...') :
userName }</Text>
<FontAwesome name="angle-right" size={25} color="#000000"/>
</View>
</TouchableOpacity>)
};
return (
<SafeAreaView style={styles.container}>
<TextInput
autoCapitalize="none"
autoCorrect={false}
clearButtonMode="always"
placeholder="Search friend"
style={styles.chatsearch}
/>
{contacts ?
(<FlatList
data={contacts.payload.allContact}
renderItem={(item, index) => renderItem(item, index)}
keyExtractor={item => item.id}
style={styles.FlatListContainer}
/>) : (<Text style={styles.FlatListContainer}></Text>)
}
</SafeAreaView>
);
}
const styles = StyleSheet.create({});
ChatScreen.propTypes = {
isAuthenticated: PropTypes.bool,
auth: PropTypes.object,
};
const mapStateProps = state => ({
auth: state.auth,
chat: state.chat
});
export default connect(mapStateProps, {getChatContacts} )(ChatScreen);
Redux Action
export const getChatContacts = () => async dispatch => {
const config = {
header: {
"Content-Type": "application/json"
}
}
try {
const res = await axios.get(API_LINK +"/users/getChatContacts",);
dispatch({
type: GET_CONTACT_CHAT,
payload: res.data
});
} catch (err){
console.log(err)
dispatch({
type: ERROR_FAMILY_PARENT,
payload: { msg: err.response, status: err.response}
});
}
};

Filter button with react native

I would like to create a button in order to filter some data
I am able to see everything I want to see and I can use the filter on "componentDidMount() setData"
I would use my function on "TouchableOpacity onPress={this.buttonFilterMac}"
Constructor :
constructor(props) {
super(props)
this.state = {
data: []
}
}
My Data :
componentDidMount() {
const url = 'https://next.json-generator.com/api/json/get/V1geuzIDB'
fetch(url)
.then((response) => response.json())
.then((responseJson) => {
this.setState({
data: responseJson.Employe
// data: responseJson.Employe.filter(x => x.Prenom == 'Abrahim')
})
})
.catch((error) => {
console.log('====================================');
console.log(error);
console.log('====================================');
})
}
My Fonction
buttonFilterMac({ item }){
data: responseJson.Employe.filter(x => x.Prenom == 'Abrahim')
}
My button with a image
<TouchableOpacity onPress={this.buttonFilterMac}>
<Image
source={button1}
style={{ width: 160, height: 18 }}
resizeMode="contain"
//style={styles.image_car}
/>
thank a lot for your help
On fetch you need to set the list of data:
this.setState({ data: responseJson.Employe })
When you click filter, you need to set state again with the filtered data in roder to see change in you Component:
buttonFilterMac = () => {
this.setState({ data: this.state.data.filter(x => x.Prenom === 'Abrahim') })
}
How ever, keep in mind when you set your filtered data, the ones not included in the filtered data would be lost. So maybe you could set the original data in a local variable after fetch or in the state. Then you could work with it later.
An example data array for a FlatList:
render() {
const data = this.state.filteredData || this.state.originalData;
return <FlatList data={data} />;
}
With the filter button you can turn on/off the filter, keep in mind to unset this.state.filteredData in order to display this.state.originalData.

Unhandled Promise Rejection : Existing value for key "Favorites" must be of type null or array, revived string

my problem is quite simple but I'm new to react native dev. I'd like to save multiple elements with AsyncStorage (I'm using react-native-simple-store
a library that works like a wrapper but it's same logic) I want display all items for a key in a list , my code look like this:
constructor(props) {
super(props)
this.state = {
UserInput: "",
}
}
SaveValue = () => {
store.push('Favorites', this.state.UserInput)
Keyboard.dismiss()
};
FetchValue = () => {
store.get('Favorites').then((value) => {
this.setState({
favs: value
});
}).done();
};
Same thing with AsynStorage, it just update the item which is not my goal, I'd like to add a new one
SaveValue = () => {
AsyncStorage.setItem("Favorites", this.state.UserInput);
Keyboard.dismiss()
};
FetchValue = () => {
AsyncStorage.getItem("Favorites").then((value) => {
this.setState({
favs: value
});
}).done();
};
This part is my view where I try to display data, you can also see that I use a text input and two buttons one to save and the other to display an array of items stored
render() {
return (
<View>
<TextInput
onChangeText={(UserInput) => this.setState({UserInput})}
placeholder= "Type something"
value={this.state.UserInput} />
<TouchableOpacity
onPress={this.SaveValue}>
<Text>Save</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={this.FetchValue}>
<Text>Fetch</Text>
</TouchableOpacity>
<Text>{this.state.favs}</Text>
</View>
);
}
At this point I can see only one item, I tried to figure it out and saw that I have to use another method called push but when I changed save by push it throw me an error
Unhandled Promise Rejection : Existing value for key "Favorites" must be of type null or array, revived string.
Thanks!
it will work :)
renderFavorites = () => {
AsyncStorage.getItem("Favorites").then((favs) => {
favs.map((fav) => {
return (<Text> {fav} </Text>);
});
});
}
render() {
return (
<View>
<TextInput
onChangeText={(UserInput) => this.setState({UserInput})}
placeholder= "Type something"
value={this.state.UserInput} />
<TouchableOpacity
onPress={this.SaveValue}>
<Text>Save</Text>
</TouchableOpacity>
<TouchableOpacity
onPress={this.FetchValue}>
<Text>Fetch</Text>
</TouchableOpacity>
{this.renderFavorites()}
</View>
);
}
Solution using JSON:
SaveValue = () => {
const newFavs = [...this.state.favs, this.state.UserInput];
this.setState({ favs: newFavs, UserInput: '' }, () => {
AsyncStorage.setItem("Favorites", JSON.stringify(this.state.favs));
Keyboard.dismiss()
});
};
FetchValue = () => {
AsyncStorage.getItem("Favorites").then((value) => {
this.setState({
favs: JSON.parse(value)
});
}).done();
};