useQuery renders when state changes - react-native

I want to useQuery renders whenever the state changes
is there any option in useQuery hook
`export const Search = ({ navigation }) => {
const [search, setSearch] = useState();
const [dismiss, setDismiss] = useState(false);
const [searchResult, setSearchResult] = useState();
const searchHander = (query) => {
setSearch(query)
setDismiss(true)
}
const searching = useQuery(['searching', search], () => api.search(search));
useMemo(() => {
setSearchResult(searching?.data ? searching?.data?.results : []);
}, [searching?.data])
const searchResults = ({ item }) => {
return <View style={{ marginVertical: 10 }}><SearchResults navigation={navigation} data={item} /></View>
}
const desmiss = useRef(null);
return (...)}`
useQuery is not depend to state

I don't fully understand the question:
I want to useQuery renders whenever the state changes
I'm just assuming you want to refetch when the state changes, because when state changes, your component does render.
For this, all you need to do is add search to the queryKey, which you have already done.
Further, I can see that you are calling setSearchResults in useMemo which is a) unnecessary because react-query already gives you the result and b) violates component purity because you call setState during render.
I think the component should just be:
const [search, setSearch] = useState();
const [dismiss, setDismiss] = useState(false);
const [searchResult, setSearchResult] = useState();
const searchHander = (query) => {
setSearch(query)
setDismiss(true)
}
const searching = useQuery(['searching', search], () => api.search(search));
const searchResult = searching?.data?.results ?? []
Then you can work with searchResult, and whenever setSearch is called, your query will refetch.

Related

Problem rendering flatlist data with api sauce

So i'm building a very simple mobile app that fetches clients data .so far everything is working fine. The only problem i keep encountering is rendering Flatlist data using api sauce. My api call is successful, i receive all the data from the database. When i reload expo the data doesn’t show yet when i hit save ‘cmd + s’ of my code the data get displayed successfully displayed. So i don’t understand why my data doesn’t get rendered when the component get mounted. here's my code
// i built hook for my api calls
import useApi from "../../hooks/useApi";
const getFoldersApi = useApi(foldersApi.getFolders);
const [foldersList, setFoldersList] = useState([]);
useEffect(() => {
getFoldersApi.request();
setFoldersList(getFoldersApi.data);
}, []);
<FlatList
style={styles.folders}
/// here reside the problem
data={foldersList}
keyExtractor={(folder) => folder.Guid}
renderItem={({ item, index }) => (
<Card
title={item.Nom}
image={folderIcon}
index={index}
folderType={item.TypeDossier}
folderState={item.EtatDossier}
depositDate={item.DatedepoDossier}
shippingType={item.TypeManifeste}
vendor={item.Fournisseur}
onPress={() => navigation.navigate("Détails", item)}
/>
)}
/>
my api hook
import { useState } from "react";
export default useApi = (apiFunc) => {
const [data, setData] = useState([]);
const [error, setError] = useState(false);
const [loading, setLoading] = useState(false);
const request = async (...args) => {
setLoading(true);
const response = await apiFunc(...args);
setLoading(false);
if (!response.ok) return setError(true);
setError(false);
setData(response.data);
};
return { data, error, loading, request };
};
here's what i mean if any of you didn't understand my problem

How can I solve undefined is not an object (evaluating 'route.params.data') in react native?

I'm not so experienced in React Native, I'm working on my app and I'm getting this error but I don't know how I can solve it. Please help.
Below is part of my code:
const HomeScreen = ({ route, navigation }) => {
const [{ ios, appSettings, rtl_support }, dispatch] = useStateValue();
const [categoryData, setCategoryData] = useState({ 0:
route.params.data });
const [currentCategory, setCurrentCategory] = useState([]);
const [loading, setLoading] = useState(false);
const [bottomLevel, setBottomLevel] = useState(false);
You are not passing data parameter to Home screen component that's why it mentioning it as undefined.
You must use your code in this way in order to ignore errors
const HomeScreen = ({ route, navigation }) => {
const { data } = route.params; // Here data prop can be undefined if you not pass it to this component as parameter
// navigation.navigate('HomeScreen', {data: 'whatever'})
const [{ ios, appSettings, rtl_support }, dispatch] = useStateValue();
const [categoryData, setCategoryData] = useState({ 0: data });
const [currentCategory, setCurrentCategory] = useState([]);
const [loading, setLoading] = useState(false);
const [bottomLevel, setBottomLevel] = useState(false);
}
Updated
If this is the first screen then you don't need to use route.
const HomeScreen = ({ navigation }) => {
const [{ ios, appSettings, rtl_support }, dispatch] = useStateValue();
const [categoryData, setCategoryData] = useState({ 0: 'whatever here' });
const [currentCategory, setCurrentCategory] = useState([]);
const [loading, setLoading] = useState(false);
const [bottomLevel, setBottomLevel] = useState(false);
}
I hope you got it!

How to pass data from async function to Drawer Navigator in React Native

im a new to react native but trying to build my own application.
I'm trying to pass storeKey and userName obtained from DB to CustomDrawer and Drawer.Screen so I don't need to repeat the function everytime.
so, it's working inside HomeScreen, console.log prints proper value. However, when I pass it in Drawer.Screen 'stock', and then print it in that module, it shows empty array.
How can I pass value from async to drawer navigator properly?
and how can I pass it to CustomDrawer? will {...props} already contain the value?
When I print props.params in the CustomDrawer module, it only says undefined..
const HomeScreen = ({ navigation }) => {
const [storeKey, setStoreKey] = useState([]);
const [userName, setName] = useState([]);
useEffect(async() => {
let isMounted = true;
if(isMounted){
console.log('zzzz')
const auth = getAuth();
const user = auth.currentUser;
if(user !== null){
const email = user.email;
const UserInfo = await getDoc(doc(db, 'users', email));
if(UserInfo.exists()){
setName(UserInfo.data().name);
setStoreKey(UserInfo.data().storeKey)
return () => {
isMounted = false
}
}
else{
console.log('None')
}
}
}
}, [storeKey]);
console.log('this',storeKey)
return (
<Drawer.Navigator drawerContent={props => <CustomDrawer {...props} />} screenOptions={headerStyles} initialRouteName={HomeScreen} >
<Drawer.Screen name='Search' component={SearchScreen} options={QuitIcon}/>
<Drawer.Screen name='Stock' component={StockScreen} options={QuitIcon} initialParams={{storeKey: storeKey}}/>
</Drawer.Navigator>
)
}
Even if the UseEffect is async or none the following code will be the same,
when calling the console.log('this', storeKey) the data is not yet in the state, to wait the useEffect run before continue the code, you have to add an empty array as a second argument in the useEffect function like this :
useEffect(() => {
}, []) // <-- empty array here
by this way your useEffect will be run only the first render of the app and the program will wait the useEffect to be run before continue.

How to receive one callback from three simultaneous events in React Native?

I'm listening to three different events that happen simultaneously and I want to get some data from each of these events. However, I want to receive the latest data from all three events at once.
I tried using useEffect but, of course, this is triggering the callback at least three times, instead of just once.
const [key, setKey] = useState('');
const [text, setText] = useState('');
const [position, setPosition] = useState(0);
const onKeyPress = ({ nativeEvent: { key } }) => setKey(key);
const onChangeText = text => setText(text);
const onSelectionChange = ({ nativeEvent: { selection: { start, end } } }) => {
start === end && setPosition(start);
}
useEffect(() => {
// I want to do stuff with the latest key, text and position.
// However, this is called more than once when typing.
}, [key, text, position]);
// ..
<TextInput
onChangeText={onChangeText}
onKeyPress={onKeyPress}
onSelectionChange={onSelectionChange}
/>
How can I achieve this?

React native - how to refresh screen when message has been sent?

so currently I have 2 simulators open. Each simulator is logged in as a different user. When I enter the chat between these 2 users, messages are getting sent live in the socket which is perfect.
My problem:
Example: if user 1 is on the all messages screen and user 2 is inside the chat. And user 2 sends user 1 a message, user 1's screen does not automatically update with the new message, I need to either scroll to refresh or navigate from one page to the other.
How should I implement the when a new message is sent it gets shown to user 1?
Here is my code:
AllMessagesScreen.js
const [posts, setPosts] = useState([]);
const [error, setError] = useState(false);
const [loading, setLoading] = useState(false);
const[page,setPage]=useState(0);
const [refreshing, setRefreshing] = useState(false);
const loadPosts = async () => {
setLoading(true);
const response = await messagesApi.getMessages();
setLoading(false);
if(refreshing) setRefreshing(false);
if (!response.ok) return setError(true);
setError(false);
setPosts(response.data)
};
useEffect(() => {
const unsubscribe = navigation.addListener('focus', () => {
loadPosts();
});
return unsubscribe;
}, [navigation]);
return(
<FlatList
data={posts}
keyExtractor={(listing) => listing.id.toString()}
renderItem={({ item,index }) => (
<MessagesList
title={item.Post.title}
subTitle={item.Messages[0].message}
onPress={() => navigation.navigate(routes.CHAT,{message:item,index})}
/>
)}
ItemSeparatorComponent={
ListItemSeparator
}
refreshing={refreshing}
onRefresh={() => {
loadPosts()
}}
/>
In other words, when a message is sent in the chat screen I want my allmessages screen to re-render, currently it is only getting render when I scroll to refresh or navigate to allmessages screen.
If you require any additional information please tell me, I will provide it immediately. Thank you
chat screen.js
function ChatScreen({route,navigation}) {
const message = route.params.message;
const [messages, setMessages] = useState([]);
const [refreshing, setRefreshing] = useState(false);
const [text, setText] = useState('');
const [loading, setLoading] = useState(false);
const [error, setError] = useState(false);
const [socket, setSocket] = useState(null);
const { user } = useAuth();
const index = route.params.index;
const updateView = route.params.updateView;
useEffect(() => {
const newsocket =io.connect("IPADDRESS")
setMessages(message.Messages)
newsocket.on('connect', msg => {
console.log(`user: ${user.id} has joined conversation ${message.id}`)
setSocket(newsocket)
newsocket.emit('subscribe', message.id);
});
newsocket.on("send_message", (msg) => {
console.log("this is the chat messages:", msg);
setMessages(messages => [msg, ...messages]);
});
return(()=>newsocket.close());
}, []);
Let's say you have the groups schema like this:
{
id: string;
name: string;
}
and messages schema like this:
{
id: string;
groupId: string;
text: string;
}
Now to recognise that a new message has been sent in a group you can add lastMessage in group schema, like this:
{
id: string;
name: string;
lastMessage: Message;
}
This way your whenever a new message is sent, respective group will change, which will make the web-socket emit an event and you will get updated data.
In you db in lastMessage field you can have foreign key to message collection, but when sending the json to frontend send the whole message object.
Also you will have to update your function for message creation to update the group too with lastMessage.
If you have creation time in messages schema, having lastMessage in group will help with sorting them too, like showing group with latest message on top.