how to reset navigation addListener when a state is changed - react-native

I want to reset navigation addListener when state is changed but It's not working
useEffect(() => {
const {page, pageIdx, tab} = pageInfo
const remove = navigation.addListener('state', ({data:{state:{routes, index}}}) => {
if(routes[index].name === name){
if(pageIdx)
getMatchItem(`usr/goods/match/buy/history/${tab}/${page}`)
else
getItem(`usr/goods/auction/bid/${tab}/${page}`)
}
return () => remove()
})
}, [pageInfo])
so I tried to return remove function when state is changed but It couldn't work

For example:
const [stateChanged, setStateChaged] = useState(false)
const [listener, setListener] = useState(null)
useEffect(() => {
if(stateChanged && listener) {
listener()
setListener(null)
}
}, [stateChanged])
useEffect(() => {
const {page, pageIdx, tab} = pageInfo
const remove = navigation.addListener('state', ({data: {state: {routes, index}}}) => {
if (routes[index].name === name) {
if (pageIdx)
getMatchItem(`usr/goods/match/buy/history/${tab}/${page}`)
else
getItem(`usr/goods/auction/bid/${tab}/${page}`)
setStateChaged(true)
}
})
setListener(remove)
}, [pageInfo])

Related

Multiple useEffect in react-native to achieve mentioned functionality

I need help with the async nature of Async storage and axios api. Here's the functionality that I am trying to achieve ->
send request to two separate api to get some data.
display that data on the screen with some additional text
api request are authenticated so a token is passed as Authentication Header
I have attached the current implementation, I am having the a number of errors in this
Errors:
Login_token not set in state after fetching from Async Storage.
Data not set in state after api call
both resulting in either failed api calls or undefined state errors on render
This is my code.
import React, { FunctionComponent, useEffect, useCallback, useState} from 'react';
import { StyleSheet, View} from 'react-native';
// chat
import { GiftedChat } from 'react-native-gifted-chat';
// navigation
import { RootStackParamList } from '../../navigators/RootStack';
import { StackScreenProps } from '#react-navigation/stack';
export type Props = StackScreenProps<RootStackParamList, "Chat">;
// api
import { Convo_details, Send_Msg, List_Msg, Expert_Public_Profile } from '../../api/UserApi';
import Spinner from 'react-native-loading-spinner-overlay';
import AsyncStorage from '#react-native-async-storage/async-storage';
import uuid from 'react-native-uuid';
const Chat: FunctionComponent<Props> = ({ navigation, route, ...props }) => {
// console.log(props.route.params);
const [login_token, setlogin_token] = useState('')
const [conversation_id, setconversation_id] = useState('')
const [conversation_details, setconversation_details] = useState({})
const [currentuser, setcurrentuser] = useState({})
const [loading, setLoading] = useState(false);
const [expertuid, setexpertuid] = useState('')
const [ExpertProfile, setExpertProfile] = useState({})
const [messages, setMessages] = useState([]);
useEffect(() => {
getlogintoken()
console.log("####################################","getlogintoken");
}, [])
/* conversationid */
useEffect(() => {
if (route.params != null) {
setconversation_id(route.params[0])
}
console.log("####################################","conversation id");
}, [])
/* expert uid */
useEffect(() => {
if (route.params != null) {
setexpertuid(route.params[1])
}
console.log("####################################","expert uid");
}, [])
/* expert public profile */
useEffect(() => {
getexpertpublicprofile()
getConvo_details()
console.log("####################################","convo_details");
}, [])
useEffect(() => {
// get current user
AsyncStorage.getItem("currentuser").then(res => {
if (res != null) setcurrentuser(res)
else alert("Current user not found")
})
console.log("####################################","current user");
}, [])
// set welcome msg
useEffect(() => {
if (Object.keys(conversation_details).length != 0 && Object.keys(ExpertProfile).length != 0)
setwelcomemsg()
}, [])
const onSend = useCallback(async (messages = []) => {
// console.log(messages[0].text);
setMessages(previousMessages => GiftedChat.append(previousMessages, messages))
const data = {
conversation_id: "f98d6851-a713-4f58-9118-77a779ff175f",//conversation_id,
message_type: "TEXT",
body: messages[0].text
}
const res: any = await Send_Msg(data, login_token)
.catch(error => {
alert(`Send_Msg -> ${error}`)
console.log(error);
return
})
if (res.status == 200) {
console.log(res.data);
} else console.log(res);
}, [])
const getexpertpublicprofile = async () => {
setLoading(true)
const res: any = await Expert_Public_Profile(expertuid, login_token)
.catch(error => {
setLoading(false)
console.log("Expert public profile ->");
alert(`Expert public profile ->${error.message}`)
console.log(error);
return
})
setLoading(false)
if (res.status === 200) setExpertProfile(res.data)
else {
alert(`get expert public profile${res.data.message}`)
console.log("getexpertpublicprofile -->");
console.log(res.data);
}
}
const getlogintoken = () => {
AsyncStorage.getItem("login_token").then(res => {
if (res != null) {
setLoading(false)
setlogin_token(res)
}
else alert("No login token found")
})
}
const getConvo_details = async () => {
setLoading(true)
const res: any = await Convo_details(conversation_id, login_token)
.catch(error => {
setLoading(false)
alert(`Convo_details-->${error.message}`)
console.log("Convo_details -->");
console.log(error);
return
})
setLoading(false)
if (res.status === 200) setconversation_details(res.data)
else {
alert(`get convo details-> ${res.data.message}`)
console.log("getConvo_details -->");
console.log(res.data);
}
}
const setwelcomemsg = () => {
try {
let user = JSON.parse(currentuser)
let messages = [
{
_id: uuid.v4().toString(),
conversation_id: conversation_details.conversation_id,
created_at: new Date(),
from: conversation_details.recipient.user_uid,
type: "TEXT",
text: `About Me - ${ExpertProfile.bio}`,
user: {
_id: conversation_details.recipient.user_uid,
}
},
{
_id: uuid.v4().toString(),
conversation_id: conversation_details.conversation_id,
created_at: new Date(),
from: conversation_details.recipient.user_uid,
type: "TEXT",
text: `My name is ${conversation_details.recipient.name}`,
user: {
_id: conversation_details.recipient.user_uid,
}
},
{
_id: uuid.v4().toString(),
conversation_id: conversation_details.conversation_id,
created_at: new Date(),
from: conversation_details.recipient.user_uid,
type: "TEXT",
text: `Hi ${user.full_name}`,
user: {
_id: conversation_details.recipient.user_uid,
}
}]
setMessages(previousMessages => GiftedChat.append(previousMessages, messages))
} catch (error) {
console.log("try -> set welcome msg");
console.log(error);
return
}
}
return (
<View style={styles.maincontainer}>
<Spinner
visible={loading}
textContent={'Loading...'}
textStyle={{ color: '#FFF' }}
/>
<GiftedChat
messages={messages}
onSend={messages => onSend(messages)}
user={{
_id: currentuser.user_uid,
}}
isTyping={false}
scrollToBottom={true}
showAvatarForEveryMessage={true}
renderAvatar={() => null}
/>
</View>
);
}
export default Chat;
const styles = StyleSheet.create({
maincontainer: {
flex: 1,
},
});
When axios returns, it usually give the response as res.data, so in your case, try either res.data or res.data.yourToken (I'm not sure how it's your object).
Gurav,
As far as your code above, The api call's will trigger even before you get currentuser or loginToken. You have to handle the api call after getting the currentuser and loginToken. This can be gracefully handled with async, await.
example code:
useEffect(() => {
getData()
}, [])
useEffect(() => {
if(login_token && currentuser) {
//The api call goes here after you get the logintoken andcurrentuser.
// The above condition is just an example but will vary based on your requirements
}
}, [login_token, currentuser])
const getData = async () => {
await getlogintoken()
await getcurrentuser()
}
const getlogintoken = async () => {
await AsyncStorage.getItem("login_token").then(res => {
if (res != null) {
setLoading(false)
setlogin_token(res)
}
else alert("No login token found")
})
}
const getcurrentuser = async () => {
await AsyncStorage.getItem("currentuser").then(res => {
if (res != null) setcurrentuser(res)
else alert("Current user not found")
})
}

react-native why I get memory leak if I use this useEffect method

why I get memomy leak if I use this code:
useEffect(() => {
if(step === 2) {
BackHandler.addEventListener('hardwareBackPress', () => handleStep1WithBackhandler());
return () => {
BackHandler.removeEventListener('hardwareBackPress', () => handleStep1WithBackhandler());
}
} else {
if(hardware === true) {
BackHandler.addEventListener('hardwareBackPress', () => false);
return () => {
BackHandler.removeEventListener('hardwareBackPress', () => false);
}
}
}
}, [step]);
if step is equal to 2 then I go back to step1 with the function. Else nothing.
Whats wrong with that?
May be due to arrow functions in addEventListener and removeEventListener
In addition to the value of the step within the eventListener you can use this approach:
Create a customHook for tracking a state to a ref.
const useStateRef = (defaultValue = null)=> {
const [value, setValue] = useState(defaulValue)
const ref = useRef()
useEffect(()=> {
ref.current = value
},[value])
return [value, setValue, ref]
}
and use it as follows
const SomeComponent = () => {
const [step, setStep, stepRef] = useStateRef(1)
const handleBackPress = React.useCallBack(() => {
if (stepRef.current === 2) {
//some logic
}
if (someWhere.hardware) {
//some logic
}
},[])
useEffect(()=> {
BackHandler.addEventListener('hadwareBackPress',handleBackPress)
return ()=> BackHandler.removeEventListener('hadwareBackPress',handleBackPress)
},[])
//some code ...
//return something ...
return null
}

React Native: No thing show on the screen after getting data from firestore

This is my code:
const [tourists, setTourists] = useState(null)
const [saved,setsave]=useState('');
const {user, logout} = useContext(AuthContext);
const [userData, setUserData] = useState(null);
const [loading, setLoading] = useState(true);
const getUser = async() => {
await firestore()
.collection('users')
.doc( user.uid)
.get()
.then((documentSnapshot) => {
if( documentSnapshot.exists ) {
console.log('User Data in BookMark', documentSnapshot.data());
const list=[];
setUserData(documentSnapshot.data());
console.log('savedPosts: ',documentSnapshot.data().savedPosts);
documentSnapshot.data().savedPosts.map((object, index) => (
firestore().collection('posts').doc(object).get().then((querySnapshot) => {list.push(querySnapshot.data())})
))
setTourists(list);
if (loading) {
setLoading(false);
}
}
})
}
useEffect(() => {
getUser();
}, []);
return (
<View style={{flex: 1, marginTop: Constants.statusBarHeight}}>
{!loading ? ((tourists ||[]).map((object, index) => (...
I have checked through the console and see that firestore worked correctly, I got the data, tourists is not null, but the screen still shows nothing. Can anybody hekp me plz !!!
The issue is in this part:
const list=[];
setUserData(documentSnapshot.data());
console.log('savedPosts: ',documentSnapshot.data().savedPosts);
documentSnapshot.data().savedPosts.map((object, index) => (
firestore().collection('posts').doc(object).get().then((querySnapshot) => {list.push(querySnapshot.data())})
))
setTourists(list);
Becase you use then the setTourists(list) will always save an empty array because then finished after you already set the value. Also a map doesn't support async calls. We need to use a for loop for this.
Change your code to something like this:
const getUser = async () => {
await firestore()
.collection("users")
.doc(user.uid)
.get()
.then(async (documentSnapshot) => {
if (documentSnapshot.exists) {
console.log("User Data in BookMark", documentSnapshot.data());
const list = [];
const posts = [];
setUserData(documentSnapshot.data());
documentSnapshot.data().savedPosts.map((object, index) => {
posts.push(object);
});
for (let i = 0; i < posts.length; i++) {
const post = posts[i];
const docSnapshot = await firestore()
.collection("posts")
.doc(post)
.get();
list.push(docSnapshot.data());
}
setTourists(list);
if (loading) {
setLoading(false);
}
}
});
};

how do I make an array in state - reactnative

I'm taking the images I uploaded to cloud storage, but the problem is the variable is not an array, so it is only storing just one url. How do I make variables with state array?
My code:
const reference = storage().ref('images');
const [imageUrl, setImageUrl] = useState();
const refer = storage().ref('images');
useEffect(() => {
try {
listFilesAndDirectories(reference).then(() => {
console.log('Finished listing');
});
refer.list().then(result => {
result.items.forEach(element => {
element.getDownloadURL().then(downloadUrl => {
setImageUrl(downloadUrl)
console.log(imageUrl)
console.log("=================")
}).catch(error =>{
alert(error)
})
})
})
} catch (error) {
alert(error);
}
}, []);
Is that what you are looking for?
const [items, setItems] = useState([]);
const handleStateChange = () => {
setItems(state => [...state, 'someNewItem']);
}
With useCallback
const handleStateChange = useCallback(function () {
setItems(state => [...state, 'someNewItem']);
}, [])

Vue + SSR | How to transfer mixin to config file?

I am writing a config for ssr
Added mixin, to replace the title and meta Announced it globally in the app.js file.
import headMixin from './util/title'
Vue.mixin(headMixin);
When you first load the page, or when you go to the root of the site, it works.
If you go to another page, it does not work (
I wanted to add it to the config file entry-client.js in the function router.onReady()
import Vue from 'vue'
import 'es6-promise/auto'
import {createApp} from './app'
import ProgressBar from './components/ProgressBar.vue'
const bar = Vue.prototype.$bar = new Vue(ProgressBar).$mount();
document.body.appendChild(bar.$el);
Vue.mixin({
beforeRouteUpdate(to, from, next) {
const {asyncData} = this.$options;
if (asyncData) {
asyncData({
store: this.$store,
route: to
}).then(next).catch(next)
} else {
next()
}
}
});
const {app, router, store} = createApp();
if (window.__INITIAL_STATE__) {
store.replaceState(window.__INITIAL_STATE__)
}
router.onReady(() => {
router.beforeResolve((to, from, next) => {
const matched = router.getMatchedComponents(to);
const prevMatched = router.getMatchedComponents(from);
let diffed = false;
const activated = matched.filter((c, i) => {
return diffed || (diffed = (prevMatched[i] !== c))
});
const asyncDataHooks = activated.map(c => c.asyncData).filter(_ => _);
if (!asyncDataHooks.length) {
return next()
}
// TODO Обсудить наличие статусбара
bar.start();
Promise.all(asyncDataHooks.map(hook => hook({ store, route: to })))
.then(() => {
bar.finish();
next()
})
.catch(next)
});
app.$mount('#app')
});
But I can not understand how to do it correctly (
Himself mixin here
const cleanMetas = () => {
return new Promise((resolve, reject) => {
const items = document.head.querySelectorAll('meta');
for (const i in items) {
if (typeof items[i] === 'object'
&& ['viewport'].findIndex(val => val === items[i].name) !== 0
&& items[i].name !== '')
document.head.removeChild(items[i])
}
resolve()
})
};
const createMeta = (vm, name, ...attr) => {
const meta = document.createElement('meta');
meta.setAttribute(name[0], name[1]);
for (const i in attr) {
const at = attr[i];
for (const k in at) {
meta.setAttribute(at[k][0], getString(vm, at[k][1]))
}
}
document.head.appendChild(meta);
};
const getString = (vm, content) => {
return typeof content === 'function'
? content.call(vm)
: content
};
export const getMeta = (vm, meta, env) => {
if (typeof meta !== 'object')
return;
if (env) {
return Object.keys(meta)
.map(value => {
return Object.keys(meta[value])
.map(key => `${key}="${getString(vm, meta[value][key])}"`)
.join(" ");
})
.map(value => ` <meta ${value} >`)
.join("\n");
} else {
return meta
}
};
const serverHeadMixin = {
created() {
const {head} = this.$options;
if (head) {
const {title} = head;
if (title)
this.$ssrContext.title = getString(this, title);
const {meta} = head;
if (meta)
this.$ssrContext.meta = `\n${getMeta(this, meta, true)}`
}
}
};
const clientHeadMixin = {
mounted() {
const vm = this;
const {head} = this.$options;
if (head) {
const {title} = head;
if (title) {
document.title = getString(this, title)
}
}
if (head) {
cleanMetas().then(() => {
const {meta} = head;
if (meta)
for (const nm in meta) {
const name = Object.entries(meta[nm])[0];
const attr = Object.entries(meta[nm]).splice(1, Object.entries(meta[nm]).length);
createMeta(vm, name, attr)
}
})
}
}
};
export default process.env.VUE_ENV === 'server'
? serverHeadMixin
: clientHeadMixin
Link to repository with full config