Async react hook - reactjs

I would like create async React hook in React-Native for get AsyncStorage data before run my fetch.
Example :
const useCallApi = async url => {
const [instance, token] = await Promise.all([
AsyncStorage.getItem('instance'),
AsyncStorage.getItem('token')
]);
const data = useFetch(`${instance}/api/v1/${url}`, {
headers: {
Authorization: `Bearer ${token}`
}
});
return data;
};
export default useCallApi;
But this hook return an error Unhandled promise rejection. I think the problem is await before useFetch hook, but how i can fix this case ?
If anyone can help me :)
Thank you community,

Why not use AsyncStorage in another way? Only after initialization is complete, you can access AsyncStorage synchronously from anywhere.Through react-native-easy-app, you can operate AsyncStorage like this
import { XStorage } from 'react-native-easy-app';
import { AsyncStorage } from 'react-native';
export const RNStorage = {
token: undefined,
isShow: undefined,
userInfo: undefined
};
const initCallback = () => {
// From now on, you can write or read the variables in RNStorage synchronously
// equal to [console.log(await AsyncStorage.getItem('isShow'))]
console.log(RNStorage.isShow);
// equal to [ await AsyncStorage.setItem('token',TOKEN1343DN23IDD3PJ2DBF3==') ]
RNStorage.token = 'TOKEN1343DN23IDD3PJ2DBF3==';
// equal to [ await AsyncStorage.setItem('userInfo',JSON.stringify({ name:'rufeng', age:30})) ]
RNStorage.userInfo = {name: 'rufeng', age: 30};
};
XStorage.initStorage(RNStorage, AsyncStorage, initCallback);

Maybe adding await before AsyncStorage helps you:
const useCallApi = async url => {
const [instance, token] = await Promise.all([
await AsyncStorage.getItem('instance'),
await AsyncStorage.getItem('token')
]);
const data = useFetch(`${instance}/api/v1/${url}`, {
headers: {
Authorization: `Bearer ${token}`
}
});
return data;
};
export default useCallApi;

const useCallApi = async url => {
let instance = null;
let token = null;
Promise.all([
AsyncStorage.getItem('instance'),
AsyncStorage.getItem('token')
]).then(d=>{
instance = d[0];
token = d[1];
}).catch(e=>throw e);
const data = useFetch(`${instance}/api/v1/${url}`, {
headers: {
Authorization: `Bearer ${token}`
}
});
return data;
};
export default useCallApi;
I think a promise needs then when it resolve and a catch for error catching

You should not implement the hooks like that, it will cause call fetch many times whenever the component which uses this hook re-render.
Try this instead:
const useCallApi = url => {
const [data, setData] = useState(null)
useEffect(() =>{
const fetchData = async () =>{
const [instance, token] = await Promise.all([
AsyncStorage.getItem('instance'),
AsyncStorage.getItem('token')
]);
// I assume that your useFetch is a hook that retruen a Promise of data
const fetchedData = await useFetch(`${instance}/api/v1/${url}`, {
headers: {
Authorization: `Bearer ${token}`
}
});
setData(fetchedData)
}
fetchData()
},[url])
return data;
};

Related

React useAsync() not receive a data that return from fetchData()

I want to load data from server before a component is loaded.
const fecthData = async () => {
const apiUrl = "http://localhost:8080/user/natt#gmail.com";
const requestOptions = {
method: "GET",
headers: {
Authorization: `Bearer ${localStorage.getItem("token")}`,
"Content-Type": "application/json",
},
};
const res = await fetch(apiUrl, requestOptions);
if (!res.ok) throw new Error(res.statusText);
console.log(res.json());
return res.json();
}
const { data, error, isLoading } = useAsync({ promiseFn: fecthData });
console.log(data)
if (isLoading) return <Grid>"Loading..."</Grid>;
if (error) return <Grid>Something went wrong: {`${error.message}`}</Grid>;
if (data) return(<Grid>"main code"</Grid>)
console.log(res.json()); is return a data from server correctly, but data varible in
const { data, error, isLoading } = useAsync({ promiseFn: fecthData });
is undefined
I try many other way,ithing useAsync is easy to understand for me (other way is bug too)
now i got solution from my friend, use state with useEffect instead of useAsync
const [isLoaded, setIsloaded] = React.useState<boolean | null>(false);
React.useEffect(() => {
const fetchData = async () => {
await getUser();
await getGender();
await getStorage();
await getGame();
setIsloaded(true);
}
fetchData();
}, []);
if (isLoaded) return(//render)

Infinite rendering of component while fetching data with useEffect hook in reactjs

When i want to fetch collections from api, infinite rendering in useEffect happening on the console. How can fix it?
const Collections = () => {
const [collections, setCollections] = useState([]);
const token = window.localStorage.getItem("token");
useEffect(() => {
fetchUsers();
},[setCollections]);
const fetchUsers = async () => {
const response = await fetch(
"https://itransition-capstone.herokuapp.com/collections/allCollections",
{
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: "Bearer " + token,
},
}
);
const data = await response.json();
setCollections(data);
console.log("Collections", data);
};
};
export default Collections;

Using Axios in useEffect from an external file

I'm trying to export an axios call from an external file to my component, in useEffect. Im exporting the function and importing in the said component. The response is "undefined".
api_call.js:
import axios from 'axios';
const accessToken = window.localStorage.getItem('accessToken')
export const getPublicCircles = async () => {
const headers = {
'Content-Type': 'application/json',
'Accept-Language': 'fr',
'Authorization': `Bearer ${accessToken}`,
}
await axios.get('https://myurl.com/api/this-info', { headers })
.then(response => console.log(response))
.catch(error => console.log('error', error))
};
( I also tried with .then((response) => return response.data.data)
component.js
import * as API from '../../api/api_call';
export default function PublicCircles() {
const [circles, getCircles] = useState('');
useEffect(() => {
const fetchData = async () => {
const response = await API.getPublicCircles();
const json = await response.json();
console.log(response)
getCircles(response);
}
fetchData()
.catch(console.error);;
}, []);
return (
<Box>
{circles === '' ? null :
<PublicCircle circles={circles} />}
</Box>
)
}
Here are the results (getting the info from the api_call.js file, not the PublicCirlces.js one.
Thank you.
The real problem here is that the function getPublicCircles returns nothing, which is why any variable to which the result of this function call is assigned as a value, will be undefined per JavaScript rules, because a function that doesn't return any value will return undefined.
It's not a good idea to use async/await and then/catch in handling a promise together. Below is the example of handling it correctly with try/catch and async/await:
export const getPublicCircles = async () => {
const headers = {
'Content-Type': 'application/json',
'Accept-Language': 'fr',
'Authorization': `Bearer ${accessToken}`,
}
try {
const data = await axios.get('https://myurl.com/api/this-info', { headers });
return data;
} catch(error) {
console.error('error',error);
}
}

How to create a global 401 unauthroized handler using React + ReactQuery + Axios stack?

So I architected frontend in the way which encapsulates every API operation tied to a single resource inside custom hook like this:
export default function useSubjects() {
const queryClient: QueryClient = useQueryClient();
const token: string | null = useStore((state) => state.user.token);
const { yearCourseId } = useParams<{ yearCourseId: string }>();
const getSubjects = async () => {
const response = await axios.get(`yearCourses/${yearCourseId}/subjects`, {
headers: { Authorization: `Bearer ${token}` },
});
return response.data;
};
const postSubject = async (subject: SubjectType) => {
const response = await axios.post(`yearCourses/${yearCourseId}/subjects`, subject, {
headers: { Authorization: `Bearer ${token}` },
});
return response.data;
};
const query = useQuery(SUBJECTS_QUERY_KEY, getSubjects);
const postMutation = useMutation(postSubject, {
onSuccess: (subject: SubjectType) => {
queryClient.setQueryData(SUBJECTS_QUERY_KEY, (old: any) => [...old, subject]);
},
});
return { query, postMutation };
}
Now what is the way to globally handle 401 unauthorized? I would like to navigate user to /login on every unauthorized request. Note that I have more hooks like this tied to other resources.
use the onError callback. You can also do this globally as a callback on the queryCache
const queryClient = new QueryClient({
queryCache: new QueryCache({
onError: error => {
// check for 401 and redirect here
}
})
})

I am trying to fetch users using Github API, but it says the token is wrong

I am try to fetch users information using github API
import React, { useEffect } from "react";
function UserResults() {
useEffect(() => {
fetchUsers();
}, []);
const fetchUsers = async () => {
const response = await fetch(`${process.env.REACT_APP_GITHUB_URL}/users`, {
headers: {
Authorization: `token ${process.env.REACT_APP_GITHUB_TOKEN}`,
},
});
const data = response.json();
};
return <div>Hello</div>;
}
export default UserResults;
And here is what I put in my env:
REACT_APP_GITHUB_TOKEN="<token>"
REACT_APP_GITHUB_URL = "https://api.github.com"
I am sure the token is correctly generated and copied.
But it seems I can't fetch the data due to some "JSON" error as it shows in the console like this.
Can anyone offers any help with this?
You need to await response.json() and update your header request
import React, { useEffect } from "react";
function UserResults() {
useEffect(() => {
fetchUsers();
}, []);
const fetchUsers = async () => {
const response = await fetch(`${process.env.REACT_APP_GITHUB_URL}/users`, {
headers: {
'Authorization': `token ${process.env.REACT_APP_GITHUB_TOKEN}`,
'Content-Type': 'application/json',
'Accept': 'application/json'
},
});
const data = await response.json();
};
return <div>Hello</div>;
}
export default UserResults;

Resources