React Native Route.params Set/ Get Asyncstorage - reactjs

const { MoodNameResult } = this.props.route.params == undefined ? this.props.route.params = "asd" : this.props.route.params;
const asd = [] + MoodNameResult;
const storeData = async (value) => {
try {
const jsonValue = JSON.stringify(value)
await AsyncStorage.setItem('#MoodNameResult', jsonValue)
} catch (e) {
// saving error
}
}
const getData = async () => {
try {
const jsonValue = await AsyncStorage.getItem('#MoodNameResult')
return jsonValue != null ? JSON.parse(jsonValue) : null;
} catch (e) {
// error reading value
}
}
console.log(getData());
On the last page "Would you like to score again?" I ask the question and if "yes" is said, I am directed to the score page with the data in the MoodNameResult. When I checked, the data in the MoodNameResult I received using Route.params is correct, but I cannot save the data from Route.params to Asyncstorage. I'm new, I always get an error when I research and apply a few resources.

Related

trying to update user profile but get error with image I can't update it

I'm trying to update user profile using react native expo I can only update all properties except image is giving me this Error :
[Unhandled promise rejection: FirebaseError: Function DocumentReference.update() called with invalid data. Unsupported field value: undefined (found in field userImg in document users ? please help
const [image, setImage] = useState(null);
const [uploading,setUploading] = useState(false)
const [ userData, setUserData] = useState(null);
useEffect(()=>{
const getUserData = async ()=>{
db.collection("users")
.doc(auth.currentUser?.uid)
.get()
.then(snap => {
setUserData(snap.data());
});
}
getUserData();
},[])
const updateProfile = async()=>{
let imgUrl = await uploadImage();
if(imgUrl == null && userData.userImg){
imgUrl = userData.userImg
}
db.collection("users")
.doc(auth.currentUser.uid)
.update({
name: userData.name,
userName: userData.userName,
email: userData.email,
phone: userData.phone,
address: userData.address,
userImg:userData.mgUrl
})
}
I can upload the image successfully but I can't fetch it from storage to fire store
const uploadImage = async ()=>{
if(image == null){
return null;
}
const blob = await new Promise((resolve, reject)=>{
const xhr = new XMLHttpRequest();
xhr.onload = function (){
resolve(xhr.response)
};
xhr.onerror = function (){
reject( new TypeError("Network request failed"))
};
xhr.responseType = "blob"
xhr.open("GET",image,true)
xhr.send(null)
});
const ref = firebase.storage().ref().child("images/" + new Date().toISOString())
const snapshot = ref.put(blob)
snapshot.on(
firebase.storage.TaskEvent.STATE_CHANGED,
()=>{
setUploading(true)
},
(error)=>{
setUploading(false)
console.log(error)
blob.close();
return;
},
()=>{
snapshot.snapshot.ref.getDownloadURL().then((url)=>{
setUploading(false);
// Alert.alert('Profile Updated', 'You profile Updated Successfully..!')
console.log('donwload:', url)
setUserData(url)
blob.close()
return null
})
}
)
}
}
so please help me out between I'm using React Native Expo and thank you so much
To start off, the error [Unhandled promise rejection: FirebaseError: Function DocumentReference.update() called with invalid data. Unsupported field value: undefined means that one or more fields has a null value but firebase doesn't allow you to store that.
In your uploadImage function you're able to upload your image fine when the image actually does exist but in cases that it doesn't you're returning null which is where the problem is. Ideally, you can return an empty string which is safe then in cases where you read the image you can just check if the string is empty or not.
Fix
Step 1
Change this
if(image == null){
return null;
}
To this
if(image == null){
return "";
}
Step 2
After you get the download URL your setUserData is replacing all the fields with the URL so consider changing it to
`
setUserData({...userData, imgUrl : url})
Step 3
Also realize that in your update() there is a typo for imgUrl change from
userImg:userData.mgUrl to userImg:userData.imgUrl to properly set the image using the step for line
Hope that fixes It :)
`
Check if below code helps you to upload a Video or Image using firebase.
const uploadImageToFirestore = async (res, type) => {
const uri = res.assets[0].uri;
const filename = uri.substring(uri.lastIndexOf('/') + 1);
const uploadUri = Platform.OS === 'ios' ? uri.replace('file://', '') : uri;
const storage = getStorage(app);
const fileRef = ref(storage, filename);
const img = await fetch(uploadUri);
const bytes = await img.blob();
let metadata;
if (type == 'video') {
if (filename.includes("mov") || filename.includes("MOV")) {
metadata = {
contentType: 'video/quicktime'
}
} else {
metadata = {
contentType: 'video/mp4',
};
}
} else {
metadata = {
contentType: 'image/jpeg',
};
}
uploadBytes(fileRef, bytes, metadata).then(async (uploadTask) => {
console.log('task', uploadTask)
getDownloadURL(uploadTask.ref).then((url) => {
if (type == 'video') {
setVideoData(url);
} else {
setImageData(url);
}
});
}).catch((err) => {
alert('Error while uploading Image!')
console.log(err);
});
}

useEffect didnt run

So i have this function that i want to run once when the app start. This function task is to create userId then i will run another function to fetch data from firebase with the userId that created before. But the fetch function didn't start or it didnt do the task well, there is no sign of error, that's what make it more confusing. If i press the fetch function by button it work correctly.
the state
const [task, setTask] = useState(); // bisa di sebut sebagai controller text input
const [taskItems, setTaskItems] = useState([]); // state untuk list task
const [userId, setUserId] = useState();
const [isLoading, setIsLoading] = useState(true);
const baseUrl =
'https://react-http-post-RANDOM_KEY-default-rtdb.firebaseio.com/task/' + userId;
this is function to create userId function on init app
const handleCreateUser = async () => {
setIsLoading(true);
try {
const value = await AsyncStorage.getItem('userId');
if (value !== null) {
setUserId(value);
} else {
const uniqueId = makeid(6);
await AsyncStorage.setItem('userId', 'user' + uniqueId);
setUserId('user' + uniqueId);
}
await fetchDatabase();
} catch (error) {
console.log('errorrr AsyncStorage' + error);
}
setIsLoading(false);
};
this is function to fetch data from firebase
const fetchDatabase = async () => {
console.log('infinite looping');
try {
const response = await fetch(baseUrl + '.json');
if (!response.ok) {
throw new Error('Something went wrong!');
}
const data = await response.json();
// looping Map/Object dengan key sebagai indexnya
const loadedTask = [];
for (var id in data) {
loadedTask.push({
key: id,
text: data[id].text,
isComplete: data[id].isComplete,
});
}
setTaskItems(loadedTask);
} catch (error) {
setError(error.message);
}
};
this is how i call the useEffect
useEffect(() => {
handleCreateUser();
}, []);
The first thing I see is that you are not using await correctly. It should be before fetchDatabase(); function that is inside handleCreateUser like so:
await fetchDatabase();
The word await is there when you have to call an asynchronous function and you have to wait for this function to be completed.
Edit
To use only one useEffect you can check if your fetch function received your data by:
// or whatever statusCode you get when the data are present
if(reponse.statusCode === 200) {
// the await is not needed because it is present for the reponse abov
const data = response.json();
// looping Map/Object dengan key sebagai indexnya
const loadedTask = [];
for (var id in data) {
loadedTask.push({
key: id,
text: data[id].text,
isComplete: data[id].isComplete,
});
}
setTaskItems(loadedTask);
}
i got the answer, by using 2 useEffect
useEffect(() => {
handleCreateUser();
}, []);
useEffect(() => {
fetchDatabase();
}, [userId]);

How to make a request again depending on a variable change in react query?

I'm trying to make a request again depending on a variable change in react query ?
I'm getting a value from a query parameter in the url , and i'm looking to redo the useQuery if this value changes / exists ,
my useQuery function looks like this :
const { tag } = router.query;
const { isLoading, error, data } = useQuery(["articles"], () =>
getRecentArticles(tag ? `${tag}` : "")
);
my function looks like this :
export const getRecentArticles = async (tag:string) => {
if (tag.length === 0) {
const response = await axios.get(`${BASE_URL}/articles/?offset=0`)
return response.data;
} else {
const response = await axios.get(`${BASE_URL}/articles/?tag=${tag}?offset=0`)
return response.data;
}
};
but that doesn't really work if my tag variable changes , Any tips on how to do so ?
You can just pass it as query key next to articles
const { tag } = router.query;
const { isLoading, error, data } = useQuery(["articles", tag], () =>
getRecentArticles(tag ? `${tag}` : "")
);
you can read more about query keys in documentation. https://tanstack.com/query/v4/docs/guides/query-keys

Handling 404 Error Response with Async/Await

I am working on a weather app and need to properly handle a 404 response from the server. There are 2 API requests made with the second one needing data from the first one.
I basically want to render "location does not exist" when there is a 404 error response. An attempt was made with try..catch which resulted in this issue: Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'coord').
Error happens for both success and failure responses.
Questions:
What does this error mean and how can I properly de-structure coord prop?
How can I properly setup try..catch to handling error response?
Bonus question: how can try..catch be made inside getForecastData function as well?
Here is the useForecast.js file containing logic and API calls:
try...catch attempt was made in getCoordinates function
import axios from "axios";
const BASE_URL = "https://api.openweathermap.org/data/2.5";
const API_KEY = process.env.REACT_APP_API_KEY;
const useForecast = () => {
// const [forecast, setForecast] = useState(null)
// const [isError, setError] = useState(false)
const getCoordinates = async (location) => {
try {
//try statement
const { data } = await axios(`${BASE_URL}/weather`, {
params: { q: location.value, appid: API_KEY }
});
console.log("call is successful", data);
} catch (data) {
//catch statement
if (!data.ok) {
console.log("location does not exist", data.message);
return;
}
return data;
}
};
const getForecastData = async (lat, lon) => {
const { data } = await axios(`${BASE_URL}/onecall`, {
params: { lat: lat, lon: lon, appid: API_KEY }
});
//if no data is not returned, call setError("Something went wrong") and return
return data;
};
const submitRequest = async (location) => {
const response = await getCoordinates(location);
const { lat, lon } = response.coord;
if (!response || !lat || !lon) return;
console.log("getCoordinates call will render", { response });
const data = await getForecastData(lat, lon);
if (!data) return;
console.log("getForecastData call will render", { data });
};
return {
submitRequest
};
};
export default useForecast;
Here is a stripped down version of the app(where screen shots were generated from): https://codesandbox.io/s/practical-pare-uc65ee?file=/src/useForecast.js
Note: API key has been removed for privacy reasons(sorry for the inconvenience)
Lastly, for context I am using the follow with React in app:
OpenWeather API: https://openweathermap.org/
Axios: https://github.com/axios/axios
You're catching the error successfully. The problem is that when it happens, you are not returning any value to
const response = await getCoordinates(location);
response will then be undefined, and coord will therefore trigger the error since undefined values can't hold any property.
To fix it, you can use the classic safety as below:
const response = await getCoordinates(location) || {};
Which essentially will make response always an object, successful or not
In addition to suggestions from #Houssam and #ale917k adjustments also had to be made with conditionals in submitRequest.
All adjustments made were:
placing return data inside try block
appending || {} to response
changing first if statement to if(!response.coord) then de-structure lat and lon.
Codebase with changes:
import axios from "axios";
const BASE_URL = "https://api.openweathermap.org/data/2.5";
const API_KEY = process.env.REACT_APP_API_KEY;
const useForecast = () => {
// const [forecast, setForecast] = useState(null)
// const [isError, setError] = useState(false)
const getCoordinates = async (location) => {
try {
const { data } = await axios(`${BASE_URL}/weather`, {
params: { q: location.value, appid: API_KEY }
});
console.log("call is successful", data);
//adjustment 1
return data;
} catch (data) {
if (!data.ok) {
console.log("location does not exist");
return;
}
}
};
const getForecastData = async (lat, lon) => {
try {
const { data } = await axios(`${BASE_URL}/onecall`, {
params: { lat: lat, lon: lon, appid: API_KEY }
});
return data;
} catch (data) {
if (!data.ok) {
console.log("something went wrong");
return;
}
}
};
const submitRequest = async (location) => {
const response = (await getCoordinates(location)) || {}; //adjustment 2
//adjustment 3
if (!response.coord) return;
const { lat, lon } = response.coord;
const data = await getForecastData(lat, lon);
if (!data) return;
};
return {
submitRequest
};
};
export default useForecast;
Screenshot of success and failure logs:

How to return boolean value from custom function in react

I have an app that takes in an object named user. The user object has userId information which is needed to get information from firestore database if the person is a paid member or not, membership is either true or false. If the person is a non-paid member than i want to display a button, and if he is a paid member, than i want the button to not be displayed. The problem i am having is how to return a boolean from the PaidMembership() function?
const App = ({ user, database }) => {
const PaidMembership = () => {
var test = null;
docRef.get().then(function(doc) {
if (doc.exists) {
test = doc.data().membership;
//console.log(paidMembership);
} else {
console.log("Error: no such document exists")
test = false;
}
})
return test;
}
return (
{ PaidMembership() ? render : dont render}
)
}
Make test variable inside state and check
const [test, setTest] = useState(null);
const App = ({ user, database }) => {
const PaidMembership = () => {
docRef.get().then(function(doc) {
if (doc.exists) {
setTest( doc.data().membership);
//console.log(paidMembership);
} else {
console.log("Error: no such document exists")
setTest(null);
}
})
return test;
}
return (
{ test ? "" : <button>show button</button>}
)
}
This is because docRef.get returns promise and you are treating it as a normal function call. Try using this :
const App = async ({ user, database }) => {
const PaidMembership = async () => {
const doc = await docRef.get();
return doc.exists;
};
return (await PaidMembership()) ? "render" : "dont render";
};

Resources