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 make react app using react router v5, and axios as api instance. I fetch the data in AppRouter file.
Here is my approuter.tsx
const AppRouter = () => {
const dispatch = useAppDispatch();
const token = useAppSelector((state) => state.user.token);
const getUser = useCallback(async () => {
const { data } = await Services.getUser();
dispatch(userAction.setUser(data));
}, [dispatch]);
useEffect(() => {
const localStorage = new LocalStorageWorker();
const storageToken = localStorage.get('token');
dispatch(userAction.setToken(storageToken));
}, [dispatch]);
useEffect(() => {
if (token) {
getUser();
console.log('Worked');
}
}, [token, getUser]);
return (
...
)
}
Actually the function work properly, but I need to refresh the page manually to run these functions. How can I make the function run without refreshing the page?
Update:
The problem is because my axios create instance. I should use interceptors to keep the data fetching in useEffect.
My instance looks like this:
(before update)
const token = localStorage.get('token');
const createInstance = () => {
const instance = axios.create({
baseURL: BASE_URL,
headers: {
'content-type': 'application/json',
Accept: 'application/json',
},
});
instance.defaults.headers.common.Authorization = `Bearer ${token}`;
return instance;
};
(after update)
const createInstance = () => {
const instance = axios.create({
baseURL: BASE_URL,
headers: {
'content-type': 'application/json',
Accept: 'application/json',
},
});
instance.interceptors.request.use(
(config) => {
const token = window.localStorage.getItem('token');
if (token) {
return {
...config,
headers: { Authorization: `Bearer ${token}` },
};
}
return null;
},
(err) => Promise.reject(err)
);
return instance;
};
And now the data fetching is work properly. Thank you
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?
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;
Working on my first project and need some help. I succeeded with React to use Spotify API to fetch my playlists. Now I want to build a search component, but I am getting a 401 returned. I assume that the problem is in my headers (Content-Type??).
import React, {useEffect, useState} from "react";
import axios from "axios";
import {useOptionContext} from "../context/SelectedOptionsProvider";
export default function ArtistOnSpotify() {
const [token, setToken] = useState("");
const [data, setData] = useState({});
const {
selectedArtist,
} = useOptionContext();
console.log("localstorage", localStorage);
console.log("token", token);
useEffect(() => {
if (localStorage.getItem("accessToken")) {
console.log(localStorage);
setToken(localStorage.getItem("accessToken"));
}
}, []);
async function ArtistOnSpotify() {
try {
console.log(token);
const response = await axios.get(`https://api.spotify.com/v1/search?query=${selectedArtist}`, {
headers: {
Authorization: "Bearer " + token,
Accept: "application/json",
"Content-Type" : "application/json",
// Content-Type : "application/json",
},
})
;
console.log(response.data);
// setData(response.data);
} catch (error) {
console.log(error);
}
;
};
return (
<div>
<button onClick={() => ArtistOnSpotify()}>klik</button>
</div>
)
}