I am trying to create a React Native app with Expo and authenticate using google. I am following this documentation. I expect response.authentication.accessToken to be a string access token, instead it is null. My error message is Typeerror: null is not an object (evaluating 'response.authentication.accesstoken')
Here is the relevant part of my code:
WebBrowser.maybeCompleteAuthSession();
export default function App() {
const [accessToken, setAccessToken] = React.useState(null);
const [user, setUser] = React.useState(null);
const [request, response, promptAsync] = Google.useIdTokenAuthRequest({
expoClientId: "[REDACTED].apps.googleusercontent.com",
webClientId: "[REDACTED].apps.googleusercontent.com",
iosClientId: "[REDACTED].apps.googleusercontent.com",
androidClientId: "[REDACTED].apps.googleusercontent.com",
});
React.useEffect(() => {
if(response?.type === "success") {
console.log(response);
setAccessToken(response.authentication.accessToken);
accessToken && fetchUserInfo();
}
}, [response, accessToken])
Why is it null?
The solution I found was to switch functions, Google.useIdTokenAuthRequest to Google.useAuthRequest. I also fixed my bundleIdentifier and android package in app.json to exactly match my slug (there were capitalization issues).
Related
Here is the new script with the find function which allows me to identify a single element of the array for sure but there is still a small problem. As you can see it's my const crypto which contains the data I want to display on the front end. However when I want to call crypto at the return level the const is not recognized.
Hello again,
I updated the script now it works I can display on the front end the data I want however I have the impression that the request to the api is executed several times when I would like there to be only one request
I put below a screen of the console.log of my script.
As you can see the data requested is displayed first as undefined then it is displayed several times, then I put blocked due to the too large number of requests made in little time
Thanks for your help
How do I make my requests :
import { useState, useEffect } from "react";
function App() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null)
useEffect(() => {
fetch("http://localhost:4500/coingeckotest")
.then(response => {
if (response.ok) {
return response.json()
}
throw response;
})
.then(data => {
setData(data)
})
.catch(error => {
console.error("Error fetching data: ", error)
setError(error)
})
.finally(() => {
setLoading(false)
})
}, [])
const uniswap = data&&data[0].tickers?.find(donne =>
donne.trade_url === 'https://app.uniswap.org/#/swap?
inputCurrency=0x2260fac5e5542a773aa44fbcfedf7c193bc2c599&
outputCurrency=ETH')
const uniprice = uniswap?.converted_last?.usd
const sushiswap = data&&data[1].tickers?.find(donne =>
donne.trade_url === 'https://app.sushi.com/swap?
inputCurrency=0x2260fac5e5542a773aa44fbcfedf7c193bc2c59
9&outputCurrency=ETH')
const sushiprice = sushiswap?.converted_last?.usd
const curvefinance = data&&data[2].tickers?.find(donne =>
donne.base === 'DAI')
const curveprice = curvefinance?.converted_last?.usd
const quickswap = data&&data[3].tickers?.find(donne =>
donne.trade_url === 'https://quickswap.exchange/#/swap?
inputCurrency=0x0d500b1d8e8ef31e21c99d1db9a6444d3adf127
0&outputCurrency=0xbbba073c31bf03b8acf7c28ef0738decf369
5683')
const quickprice = quickswap?.converted_last?.usd
console.log(uniprice)
console.log(sushiprice)
console.log(curveprice)
console.log(quickprice)
if (loading) return "Loading..."
if(error) return "Error !"
return (
<>
</>
)
}
export default App;
Thank you in advance for your answers
You can use the Array.find method to find out the first entry that matches a particular coin_id. The code for that would be:
const desiredCoinID = "something"; (determined by some user input)
const desiredCoinObject = data.find(coin => coin.coin_id === desiredCoinID);
const priceInUSD = desiredCoinObject?.tickers?.converted_last?.usd;
——-Updated Answer——-
Hi, this is my answer to your updated question. const crypto that you use is available only within the scope of the callback of the useEffect function, which is why you cannot see the results on your screen. There are two ways you can go about it:
First, you can declare crypto as a let outside the useEffect and then update it inside your useEffect. That way your crypto will have global scope. But there is a better way to do this, which is to use the useState hook.
You can declare a crypto, setCrypto using useState and then use the setter to update the value if crypto inside useEffect after the data fetching is over. Let me know if you need help writing code.
I have on my site an page where I handled File upload, but since I upgraded Firebase (I guess it was Firebase v7/8) this particular feature is not working anymore.
To handled the file upload in firebase storage I created a custom hook, where I use the useEffect because I need it to run each time there is a new file value. I passed a parametter (file) for the file I'm trying to upload and store it in database, and that way databse contains all image's url. Then I used the datas to load images in a react components.
The error I've got:
Uncaught TypeError: projectStorage.ref is not a function
Since I'm on Firebase v9 I'm lillte bit confused about it, and don't know what to change. Thank you for your help, I really appreciate =).
useStorage.jsx (custom hook)
import {projectStorage, projectFirestore, timestamp} from '../Firebase'
import { useEffect, useState } from 'react'
function useStorage(file) {
const [progress, setProgress] = useState(0);
const [error, setError] = useState(null);
const [url, setUrl] = useState(null);
useEffect(() => {
const storageRef = projectStorage.ref(file.name)
const collectionRef = projectFirestore.collection('images');
storageRef.put(file).on('state_changed', (snap) => {
let percent = (snap.bytesTransferred / snap.totalBytes) * 100;
setProgress(percent >> 0); // or Math.trunc()
}, (err) => {
setError(err);
}, async () =>{
const url = await storageRef.getDownloadURL();
const createdAt = timestamp();
collectionRef.add({ url, createdAt});
setUrl(url);
});
}, [file]);
return {progress, url, error};
}
export default useStorage;
There's a top level function uploadBytesResumable() to upload files while monitoring progress. Try refactoring the code as shown below:
import {projectStorage, projectFirestore, timestamp} from '../Firebase'
import { ref as storageRef, uploadBytesResumable } from "firebase/storage";
useEffect(() => {
// Creating a storage reference
const storageReference = storageRef(projectStorage, file.name);
// Creating an upload task
const uploadTask = uploadBytesResumable(storageReference, file);
// Monitoring upload progress
uploadTask.on("state_changed", (snapshot: any) => {
console.log(snapshot);
// render progress
});
}, [file])
Checkout the documentation on Upload files with Cloud Storage on Web.
I have a code where the user can update his credentials/personal information however I encounter a problem and managed to fix it, it was saying first argument had to be an string and I found a solution however I got an error afterwards saying "This operation is sensitive and requires recent authentication. Log in again before retrying...
Afterwards I found in some of the comments where I found my first solution the following:
user.reauthenticateWithCredential(auth.EmailAuthProvider.credential(user.email, user.password)).then(() => user.updateEmail(email)) I tried to use this but is not working I get other error afterwards and wanted to know if this was either outdated or I'm just doing this wrong.
Code
I get my auth from my firebase.js
const db = firebase.firestore();
const auth = firebase.auth();
const storage = firebase.storage();
I get my user from my App.js and then if I need it I just send it just like this:
function App() {
const [user, setUser] = useState([]);
useEffect(() => {
auth.onAuthStateChanged((authUser) => {
if (authUser) {
setUser(authUser);
} else {
setUser(false);
}
})
}, [])
return (
....
<Route path = "/Update_Profile">
<Inicio user={user}/>
<UpdateProfile user={user}/>
</Route>
...
)}
export default App;
const updateEmail = (e) => {
e.preventDefault();
if (user && (email != "")) {
user.reauthenticateWithCredential(auth.EmailAuthProvider.credential(user.email, user.password))
.then(() => user.updateEmail(email))
const ref = db.collection("usuarios").doc(user.uid)
ref.update({
email: email
})
} else {
//User is not logged in, handle that case here
}
}
Because auth is an instance of the Auth module and not the namespace of the Auth module from the Firebase Web SDK (because you've used const auth = firebase.auth()), the following value is undefined:
auth.EmailAuthProvider
This is because the firebase.auth.Auth class does not define a property EmailAuthProvider. This then means JavaScript tries to call undefined.credential(...) and throws an error.
To access the EmailAuthProvider class, you need to access it from the firebase.auth namespace directly:
firebase.auth.EmailAuthProvider
In short,
firebase.auth !== firebase.auth()
I have a code that will save user in the database on my profile screen, but the code worked fine on iOS, but on android it throws a "Possible unhandled Promise Rejection" with "TypeError: Symbol.asyncIterator is not defined."
Please how can solve the issue on Android so that it can save to database? I am working with React Native.
Here is the code snippet:
import {Auth, DataStore} from 'aws-amplify';
const ProfileScreen = () => {
const [name, setName] = useState('');
const [bio, setBio] = useState('');
const [gender, setGender] = useState();
const [lookingfor, setLookingfor] = useState();
const isValid = () => {
return name && bio && gender && lookingfor;
};
const save = () => {
if(!isValid()) {
console.warn('Not valid');
return;
}
const newUser = new User({
name,
bio,
gender,
lookingfor,
image: 'https://notjustdev-dummy.s3.us-east-2.amazonaws.com/avatars/elon.png',
});
DataStore.save(newUser);
};
return ...
I've been doing the same project. It worked for me when I did:
npm install #azure/core-asynciterator-polyfill
Then added:
import '#azure/core-asynciterator-polyfill';
at the very top of my imports in the page I was working on.
Accoding to the documentation, since save returns a promise instead of doing the opeartion itself, add await or subscribe with then to the save function;
await DataStore.save(newUser);
or
DataStore.save(newUser).then(...);
I was working on an app based on webRTC API , and working with useRef() hook in react, I got an error
Error: TypeError: myVideo.current is undefined
ContextProvider SocketContext.js:27
promise callback*ContextProvider/< SocketContext.js:23
React 5
unstable_runWithPriority scheduler.development.js:468
React 3
workLoop scheduler.development.js:417
flushWork scheduler.development.js:390
performWorkUntilDeadline scheduler.development.js:157
js scheduler.development.js:180
js scheduler.development.js:645
Webpack 21
and the code for context is
const myVideo = useRef();
//const myVideo = useRef(null); tried this also but not solved
const userVideo = useRef();
const connectionRef = useRef();
useEffect(() => {
navigator.mediaDevices.getUserMedia({ video: true, audio: true })
.then((currentStream) => {
setStream(currentStream);
myVideo.current.srcObject = currentStream;
})
.catch((err) => {
console.log("Error ", err);
})
socket.on('me', (id) => setMe(id));
socket.on('callUser', ({ from, name: callerName, signal }) => {
setCall({ isReceivingCall: true, from, name: callerName, signal });
});
}, []);
I've tried adding myVideo || myVideo.current is useRef() dependency list.
Looking a bit more into it, it seems like you can't properly use React-controlled refs within useEffect. A solution described here and several answers on this question might help you further.
In short, your useEffect gets called before the reference gets set. Instead, use a callback as reference instead:
const myVideo = useCallback(video => {
if (!video) return; // video object no longer available
// You now have the video object
// either set the `srcObject` here, or store `video` to set it later
}, []);
// somewhere else
return <video ref={myVideo} ... />;