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;
I have a small React project that I am in the process of converting to typescript. I am currently trying to convert a Context file into Typescript. For reference, here is the original JS code:
import { createContext, useCallback, useState } from "react";
import netlifyIdentity from 'netlify-identity-widget';
export const AppContext = createContext()
export function useAppContext() {
const [user, setUser] = useState(netlifyIdentity.currentUser())
const genericAuthedFetch = useCallback((
endpoint,
method = 'GET',
body = null,
) => {
if (!(!!user && !!user.token && !!user.token.access_token)) {
return Promise.reject('no user token found');
}
const options = {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'Bearer ' + user.token.access_token,
},
method,
body: body === null ? null : JSON.stringify(body),
};
return fetch(endpoint, options);
}, [user]);
const getStockData = (ticker, target) => {
var url = new URL('.netlify/functions/get-price', window.location.origin)
url.search = new URLSearchParams({ ticker, target }).toString()
return genericAuthedFetch(url);
}
const createAccount = (params) => {
return genericAuthedFetch(
new URL('.netlify/functions/create-account', window.location.origin),
'POST',
params);
}
const listAccounts = (date) => {
var url = new URL('.netlify/functions/list-accounts', window.location.origin);
url.search = new URLSearchParams({ timestamp: date.getTime() }).toString()
return genericAuthedFetch(url);
}
const loginUser = useCallback((user) => {
fetch(
new URL('.netlify/functions/make-user', window.location.origin),
{
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'Bearer ' + user.token.access_token,
},
method: 'POST'
}).then((_) =>
setUser(user))
}, [setUser])
const logoutUser = useCallback((user) => setUser(null), [setUser])
netlifyIdentity.on("login", loginUser);
netlifyIdentity.on("logout", logoutUser);
const loginPopup = () => netlifyIdentity.open('login')
const signupPopup = () => netlifyIdentity.open('signup')
const logout = () => netlifyIdentity.logout();
return {
user,
logout,
loginPopup,
signupPopup,
getStockData,
listAccounts,
createAccount
}
}
And here is the associated TS code
import React, { createContext, useCallback, useState } from "react";
import netlifyIdentity, { User } from 'netlify-identity-widget';
import { CreateAccountRequest, CreateAccountResponse, GetPriceRequest, GetPriceResponse, ListAccountsRequest, ListAccountsResponse } from "../types/types";
export interface Context {
user?: User
logout: () => void
loginPopup: () => void
signupPopup: () => void
getStockData: (req: GetPriceRequest) => Promise<GetPriceResponse>
listAccounts:(req: ListAccountsRequest) => Promise<ListAccountsResponse>
createAccount: (req: CreateAccountRequest) => Promise<CreateAccountResponse>
}
export const AppContext: React.Context<Context> = createContext({} as Context)
export function useAppContext() {
const [user, setUser] = useState(netlifyIdentity.currentUser())
const genericAuthedFetch = useCallback((
endpoint: URL,
method = 'GET',
body: any = null,
) => {
if (!user?.token?.access_token) {
return Promise.reject('no user token found');
}
const options = {
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'Bearer ' + user.token.access_token,
},
method,
body: body === null ? null : JSON.stringify(body),
};
return fetch(endpoint, options);
}, [user]);
const getStockData = (req: GetPriceRequest) => {
var url = new URL('.netlify/functions/get-price', window.location.origin)
url.search = new URLSearchParams({ ticker: req.ticker, target: req.target }).toString()
return genericAuthedFetch(url);
}
const createAccount = (req: CreateAccountRequest) => {
return genericAuthedFetch(
new URL('.netlify/functions/create-account', window.location.origin),
'POST',
req);
}
const listAccounts = (req: ListAccountsRequest) => {
var url = new URL('.netlify/functions/list-accounts', window.location.origin);
url.search = new URLSearchParams({ timestamp: req.timestamp.toString() }).toString()
return genericAuthedFetch(url);
}
const loginUser = useCallback((user: User) => {
fetch(
new URL('.netlify/functions/make-user', window.location.origin),
{
headers: {
Accept: 'application/json',
'Content-Type': 'application/json',
Authorization: 'Bearer ' + user?.token?.access_token,
},
method: 'POST'
}).then((_) =>
setUser(user))
}, [setUser])
const logoutUser = useCallback(() => setUser(null), [setUser])
netlifyIdentity.on("login", loginUser);
netlifyIdentity.on("logout", logoutUser);
const loginPopup = () => netlifyIdentity.open('login')
const signupPopup = () => netlifyIdentity.open('signup')
const logout = () => netlifyIdentity.logout();
return {
user,
logout,
loginPopup,
signupPopup,
getStockData,
listAccounts,
createAccount
}
}
The problem I am encountering is that when I use the dev server or create a production build using npm run build, the typescript version of this file becomes mangled in a strange way.
Specifically, the contents of the typescript file becomes
module.exports = "data:video/MP2T;base64,<base64 encoded typescript file>"
//////////////////
// WEBPACK FOOTER
// ./src/AppContext.ts
// module id = 115
// module chunks = 0
I have done some research, and the only thing I have found is that .ts is also the extension of MPEG transport stream, so that could partially explain it. Something thinks my typescript code is a video file, but I have no idea what is doing that or why.
How do I get this to compile correctly?
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 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;
I am trying to authenticate the user in order to get data to use to create or update meetings later. but it full of errors.
Here I am sending Post Requests in order to get the AccessToken and then get the UserData as props.
export async function getServerSideProps(res){
const oauth = async() => {
const zoomUserData = [];
const b = Buffer.from(process.env.ZOOM_API_KEY + ":" + process.env.ZOOM_API_SECRET);
const zoomRes = await fetch(`https://zoom.us/oauth/token?grant_type=authorization_code&code=${req.body.code}&redirect_uri=${process.env.ZOOM_REDIRECT_URL}`, {
method: "POST",
headers: {
Authorization: `Basic ${b.toString("base64")}`,
},
});
const zoomData = await zoomRes.json();
const zoomUserRes = await fetch("https://api.zoom.us/v2/users/me", {
method: "GET",
headers: {
Authorization: `Bearer ${zoomData.access_token}`,
},
});
const zoomUserData = await zoomUserRes.json();
/*
Encrypt and store below details to your database:
zoomUserData.email
zoomUserData.account_id
zoomData.access_token
zoomData.refresh_token
zoomData.expires_in // convert it to time by adding these seconds to current time
*/
}
return{
props:{zoomUserData}
}
}
and then i am passing the props to a page component like that :
export default function Meeting({zoomUserData}) {
const router = useRouter();
useEffect(() => {
if (router.query.code) {
fetch('/connectZoom',
{ method: 'POST',
headers: {
'ContType': 'application/json',
},
body: JSON.stringify({ code: router.query.code }),
}).then(() => {
console.log("success")
}).catch(() => {
console.log("No!")
});
}
}, [router.query.code]);
console.log(zoomUserData)
return (
<a href={`https://zoom.us/oauth/authorize?response_type=code&client_id=${process.env.ZOOM_API_KEY}&redirect_uri=${process.env.ZOOM_REDIRECT_URL}`}>
Connect Zoom
</a>
)
}