Looking for the best way to accomplish the following.
The goal is to, when this screen loads:
Retrieve the user's auth token from async storage, THEN
Hit an API with the auth token to grab some user details (in this case userId)
I'm also trying to useEffect so these only run once.
Function 1:
const getUserToken = async () => {
try {
const userToken = await AsyncStorage.getItem("userToken", userToken);
setUserToken(userToken);
} catch (err) {
console.log("err retrieving token " + err);
}
Function 2:
const getUserId = async () => {
try {
let response = await xano.get("/auth/me", {
headers: { Authorization: userToken },
});
setUserId(response.data.id);
console.log(userId);
} catch (err) {
console.log("getUserId err " + err);
console.log(err.data);
}
};
Function 3:
useEffect(() => {
getUserToken();
getUserId();
}, []);
You need to await those async functions in the useEffect hook.
useEffect(async () => {
await getUserToken();
await getUserId();
}, [])
Related
In the code snippet you see, I am trying to reach the data that I have determined through asyncStorage in the getToken and `` functions, but when I open the page with these codes from the emulator, the data is empty for the first time, and then when I do ctrl+s from the editor, the data is full. What is the reason for this problem?
App.js Page
getToken: async () => {
const token = AsyncStorage.getItem('userToken');
return token;
},
getMail: async () => {
const mail = AsyncStorage.getItem('userMail');
return mail;
},
OrderListScreen Page
getToken().then((res) => {
if(res){
setToken(res);
console.log(token)
}else {
setToken('');
}
});
getMail().then((res) => {
if(res){
setMail(res);
console.log(mail)
}else {
setMail('');
}
});
Apply await before using AsyncStorage.getItem:
getToken: async () => {
const token = await AsyncStorage.getItem('userToken');
return token;
},
getMail: async () => {
const mail = await AsyncStorage.getItem('userMail');
return mail;
},
In the log you'll not get the updated state in next line of state setter.
getToken().then((res) => {
if(res){
setToken(res);
console.log(token); //You'll never get this value here because state updates are asynchronous in React
console.log("res : ", res);
}else {
setToken('');
}
});
getMail().then((res) => {
if(res){
setMail(res);
console.log(mail)//You'll never get this value here because state updates are asynchronous in React
console.log("Email Res : ", res);
}else {
setMail('');
}
});
I can't figure out why the await function setDoc is not completed in my example below when I launch my react native app for the first time.
When I launch it a second time however, it works well.
Can you help me?
useEffect(() => {
registerForPushNotificationsAsync().then(async token => {
// The following gets called
console.log("Before await")
// The following does not complete when I first launch the app.
await setDoc(doc(db, "devices", token), { test: "test" })
.then(x => {
// The following does not get called
console.log('Sucess')
})
.catch(error => {
// The following does not get called
console.log('Error')
})
// The following does not get called
console.log("After await")
});
return () => {};
}, []);
with registerForPushNotificationsAsync defined outside useEffect as:
async function registerForPushNotificationsAsync() {
...
return token;
}
Thank you.
Try moving the async function outside of the useEffect function:
const someAsyncFunc = async () => {
console.log("Before await")
try {
const token = await registerForPushNotificationsAsync();
await setDoc(doc(db, "devices", token), { test: "test" })
console.log('Success')
} catch (error) {
/// do error handling
console.log(error);
}
console.log("After await")
}
useEffect(() => {
someAsyncFunc();
}, []);
use async await as follows.
useEffect(() => {
registerForPushNotificationsAsync().then(async (token) => {
// The following gets called
console.log('Before await');
try {
await setDoc(doc(db, 'devices', token), { test: 'test' });
console.log('Sucess');
} catch (error) {
console.log('Error');
}
// The following does not get called
console.log('After await');
});
return () => {};
}, []);
If there a reason why you want to use await there ?
Otherwise you should try to do this using only .then and syncronious code :
useEffect(() => {
return registerForPushNotificationsAsync().then(async token => {
// The following gets called
console.log("Before await")
// The following does not complete when I first launch the app.
return setDoc(doc(db, "devices", token), { test: "test" })
.then(x => {
// The following does not get called
console.log('Sucess')
})
.then(() => {
// The following does not get called
console.log("After await")
return () => {};
})
.catch(error => {
// The following does not get called
console.log('Error')
})
});
}, []);
I'm going to use Axios to communicate API.
But that kind of error keeps coming out. I don't understand this problem. I searched on the Internet and tried everything. Help me.
All I want is to click on that button to see the low value in the developer tool.
useEffect(() => {
setJwt(getClientCookieFromClient('jwt'));
}, []);
const customFetch = async () => {
const res = await axios
.get(`${process.env.NEXT_PUBLIC_WECODE_URI}/subscription/master_table`, {
headers: {
Authentication: jwt,
},
})
.then((res) => res.data);
if (!res.data.success) {
alert(res.data.message);
}
};
...
<button onClick={() => customFetch()}>API호출버튼</button>
Alway wrap await inside try/catch block.
const customFetch = async () => {
try {
const res = await axios
.get(`${process.env.NEXT_PUBLIC_WECODE_URI}/subscription/master_table`, {
headers: {
Authentication: jwt,
},
})
.then((res) => res.data);
if (!res.data.success) {
alert(res.data.message);
}
} catch (error) {
console.log(error);
// Do something with error
}
};
Try
useEffect(() => {
setJwt(getClientCookieFromClient('jwt'));
}, []);
const customFetch = async () => {
const res = await axios.get(`${process.env.NEXT_PUBLIC_WECODE_URI}/subscription/master_table`, {
headers: {
Authentication: jwt,
},
});
if (!res.data.success) {
alert(res.data.message);
}
};
Note:
not sure about you response structure. Current code works as expected for structure:
res = { data: { data: {success: true}}}
if it is not so, then use if statement as !res.success
useEffect(() => {
setJwt(getClientCookieFromClient('jwt'));
}, []);
const customFetch = async () => {
const res = await axios
.get(`${process.env.NEXT_PUBLIC_WECODE_URI}/subscription/master_table`, {
headers: {
Authentication: jwt,
},
})
.then((res) => res.data)
.catch((err) => console.log("Error while fetching",err)); //<--- use .catch for catching error
if (!res.data.success) {
alert(res.data.message);
}
};
I have a function, that connects to the API and returns the data:
import {API_KEY, API_URL} from "./constants";
// /**
// * Fetch all tasks
// * #param {function} successCallback - Function that saves incoming data
// */
export const getOperations = async (id, successCallback) => {
try {
const response = await fetch(`${API_URL}/tasks/${id}/operations`, {
headers: {
Authorization: API_KEY,
},
});
const data = await response.json();
if (data.error) {
throw new Error('Error!');
}
successCallback(data.data);
} catch (err) {
console.log(err);
}
};
Then, in one of my react component i call that function to get a data from the specified API:
The props is a required ID.
const [operations, setOperations] = useState([])
console.log(props)
useEffect(() => {
try {
getOperations(data => (props, setOperations(data)))
} catch(e) {
console.log(e)
}
}, [])
The problem is, that my API looks like:
`...api/tasks/function%20(data)%20%7B%20%20%20%20%20%20%20%20return%20props,%20setOperations(data);%20%20%20%`20%20%20%7D/operations`
So i receive 400 error.
Could someone explain me how to get API URL in this situation like:
/api/tasks/{id}/operations
Thanks in advance.
Rather than passing the callback to the result of the function, you could just return the data.
export const getOperations = async (id) => {
try {
const response = await fetch(`${API_URL}/tasks/${id}/operations`, {
headers: {
Authorization: API_KEY,
},
});
const data = await response.json();
if (data.error) {
throw new Error('Error!');
}
return data.data;
} catch (err) {
console.log(err);
}
};
useEffect(() => {
async function apiCall() {
try {
const data = await getOperations(props.id);
setOperations(data)
} catch(err) {
console.log(err)
}
}
apiCall();
}, [props.id])
I have an async await function that handles form submission in React Native:
const handleSubmit = async () => {
const credentials = { email, password }
try {
login(credentials)
} catch {
console.error('ERROR')
//external function to reset form
resetForm()
return
}
// User authenticated, go to home screen
await goToHomeScreen()
}
Where login(), which makes the API call, is
const login = (credentials) => {
axios
.post(`${MY_API}/login`, credentials)
.then((res) => {
console.log(res.data)
})
.catch(() => {
throw 'Error'
})
}
The idea is that if the authentication call fails, my login() throws an error, which should run the return in my handleSubmit's catch {}, ending the function. However, the catch never runs, and goToHomeScreen() runs. What am I doing wrong?
not just return but do something
axios
.get(url)
.then((response) => {
console.log('response', response);
}
.catch((error) => {
console.log('CATCH');
window.alert('CATCH');
}
Try this, it is working for me
const login = (credentials) => {
axios
.post(`${MY_API}/login`, credentials)
.then((res) => {
console.log(res.data)
})
.catch((error ) => {
return Promise.reject(error);
})
}
since you are using async-await, you can call login as:
const handleSubmit = async () => {
const credentials = { email, password }
try {
await login(credentials)
} catch {
console.error('ERROR')
//external function to reset form
resetForm()
return
}
// User authenticated, go to home screen
await goToHomeScreen()
}
const login = async (credentials) => {
return await axios.post(`${MY_API}/login`, credentials);
}
it will solve the issue