How can I receive the async data as the resolved value? - javascript

I'm trying to read files and convert them to a json, then upload them to a server. But I can't seem to be able to get the data back that isn't a promise. Can you point to what I'm doing wrong?
const onSubmit = async (formData: FormValues) => {
remove();
append(defaultFormValues.documents[0] as object);
setIsLoading(true);
const objToUpload = {
name: formData.documentName,
type: formData.documentType,
contents: [
formData.documents.map(async (document) => {
return {
language: document.language,
data: await readFromFile(document.file[0]),
actions: await readFromFile(document.actions[0]),
};
}),
],
};
console.log(objToUpload);
}
};

const onSubmit = async (formData: FormValues) => {
remove();
append(defaultFormValues.documents[0] as object);
setIsLoading(true);
const data = await Promise.all(formData.documents.map(async (document) => {
return {
language: document.language,
data: await readFromFile(document.file[0]),
actions: await readFromFile(document.actions[0]),
};
}));
const objToUpload = {
name: formData.documentName,
type: formData.documentType,
contents: data,
};
console.log(objToUpload);
};

Related

How to fetch data from the Jikanapi

I want to call an API here
https://api.jikan.moe/v4/top/anime to get the data in raw format and then create an array of only useful data out of it. What is the reason the data is not being consoled
const initialAnime = {
anime: [],
genresLoaded: false,
genres: [],
};
function createAnimeFromRawData(rawData, animeArray) {
const data = rawData.data;
data.forEach((animeData) => {
const anime = {
mal_id: animeData.mal_id,
title: animeData.title,
title_english: animeData.title_english,
type: animeData.type,
episodes: animeData.episodes,
status: animeData.status,
duration: animeData.duration,
rating: animeData.rating,
rank: animeData.rank,
synopsis: animeData.synopsis,
};
console.log(animeArray);
animeArray.push(anime);
});
}
const RawdataAnime = async (api, genre, paging) => {
const Animearray = [];
for (let i = 1; Animearray.length < 60 && i < 10; i++) {
const {
data: { results },
} = await axios.get(`${api}`);
createAnimeFromRawData(results, Animearray);
}
return Animearray;
};
export const fetchAnime = createAsyncThunk(
"myanimelist/topAnime",
async (thunkAPI) => {
const {
myanimelist: { genres },
} = thunkAPI.getState();
return RawdataAnime(`https://api.jikan.moe/v4/top/anime`, genres, false);
}
);
const animeSlice = createSlice({
name: "Myanimelist",
initialState: initialAnime,
extraReducers: (builder) => {
builder.addCase(getGenresAnime.fulfilled, (state, action) => {
state.genres = action.payload;
state.genresLoaded = true;
});
builder.addCase(fetchAnime.fulfilled, (state, action) => {
state.anime = action.payload;
});
},
});
export const store = configureStore({
reducer: {
netflix: netflixSlice.reducer,
anime: animeSlice.reducer,
},
});
I tried the code above to get an array of only useful parts of data in the code but there was nothing in the console. There was no error and no output.
Whereas the response.data will be something similar to the json below::
{
"pagination":{
...
},
"data":[
...
],
"links":{
...
},
"meta":{
...
}
}
I believe the error is in the snippet
const { data: { results }} = await axios.get(`${api}`); // There are no results in the returned content
createAnimeFromRawData(results, Animearray);
Try something like
const { data } = await axios.get(`${api}`); // Equivalent to response.data
const results = data?.data || []
createAnimeFromRawData(results, Animearray);

When I log Array there's an object inside, but when I'm trying to access that object it returns me undefined

This is my cache "component":
// imports
const useCache = (cacheName: string, url: string) => {
const cacheArray: Array<Object> = []
const getAllCaches = async () => {
const cacheNames = await caches.keys();
for (const cname of cacheNames) {
const cacheStorage = await caches.open(cname);
const cachedResponse = await cacheStorage.match(url);
const cdata = await cachedResponse?.json()
cacheArray.push({name: cname, data: cdata})
}
}
useEffect(() => {
getAllCaches()
.catch(err => console.log(err))
}, [])
const addCache = (response: any) => {
const data = new Response(JSON.stringify(response));
if ('caches' in window) {
caches.open(cacheName).then((cache) => {
cache.put(url, data);
});
}
const finalData = {name: cacheName, data: response}
cacheArray.push(finalData)
return data
}
const getCache = (cacheName?: string) => {
if (cacheName) {
return cacheArray.filter((i: any) => i.name === cacheName)[0]
}
else {
return cacheArray
}
}
const removeCache = (cacheName: string) => {
caches.delete(cacheName).then(function (res) {
return res;
});
}
return [
getCache as (cacheName?: any) => any,
addCache as (response: any) => any,
removeCache as (cacheName: any) => any
]
};
export default useCache;
Now here's code in my home component:
const [getCache, addCache, removeCache] = useCache("user", "http://localhost:3000")
useEffect(() => {
console.log(getCache())
console.log(getCache()[0])
console.log(getCache().length)
// the rest of code, not matter
and when I run home component (with vite and preact) it logging me Array, then unfedinfed, then 0 (but second should return object, and third should return 1) also I attached a screen from console.
Why it's returning me undefined and 0 length when it should return object and 1?
I'm using preact, vite, newest nodejs, typescript

Api fetch on gatsby producing error in GraphQL

This is the code I tried in gatsby-node.js, using gatsby develop to interface with graphql... I'm trying to source data from a blockchain indexer to display on my website.
const fetch = require('node-fetch');
const NODE_TYPE = 'objkt';
exports.sourceNodes = async ({ actions, createContentDigest, createNodeId }) => {
const { createNode } = actions;
const response = await fetch('https://staging.api.tzkt.io/v1/bigmaps/523/keys?value.issuer=tz1V9ZviaGUWZjGx4U7cGYFEyUGyqpFnVGXx&active=true');
const json = await response.json();
const { results = [] } = json;
const objkt = await Promise.all(results.map(async result => {
const { url } = result;
const objResponse = await fetch(url);
return await objResponse.json();
}));
objkt.forEach((node, index) => {
createNode({
...node,
id: createNodeId(`${NODE_TYPE}-${node.id}`),
parent: null,
children: null,
internal: {
type: NODE_TYPE,
content: JSON.stringify(node),
contentDigest: createContentDigest(node)
}
});
});
};
creates error:
{
"errors": [
{
"message": "Syntax Error: Expected Name, found \"}\".",
"locations": [
{
"line": 4,
"column": 3
}
],
"stack": [
"GraphQLError: Syntax Error: Expected Name, found \"}\".",
data I'm trying to source
I'm very lost as to why this error happens...
SOLUTION:
const fetch = require("node-fetch")
const NODE_TYPE = `objkt`
exports.sourceNodes = async ({
actions,
createContentDigest,
createNodeId,
}) => {
const { createNode } = actions
const response = await fetch(
"https://staging.api.tzkt.io/v1/bigmaps/523/keys?value.issuer=tz1V9ZviaGUWZjGx4U7cGYFEyUGyqpFnVGXx&active=true"
)
const objkt = await response.json()
objkt.forEach((node, index) => {
createNode({
...node,
id: createNodeId(`${NODE_TYPE}-${node.id}`),
parent: null,
children: [],
internal: {
type: NODE_TYPE,
content: JSON.stringify(node),
contentDigest: createContentDigest(node),
},
})
})
}
exports.onPreInit = () => console.log("Loaded gatsby-node")
GraphQL code:
query MyQuery {
objkt {
value {
issuer
objkt_id
objkt_amount
xtz_per_objkt
}
internal {
content
contentDigest
}
}
}

How to make an HTTP hook reusable on the same component

I have an HTTP hook that can be consumed like this:
const { data, error, isLoading, executeFetch } = useHttp<IArticle[]>('news', []);
In the same component, I want to trigger another API call to POST data and update one of the articles:
const handleChange = (article: IArticle, event: React.ChangeEvent<HTMLInputElement>) => {
executeFetch(`updateNews?id=${article.id}`, { method: 'post', data: { isRead: event.target.checked }});
};
return (
<>
<div className={classes.articleListHeader}>
<h1>Article List</h1>
<small className={classes.headerSubtitle}>{data.length} Articles</small>
</div>
<ul>
{data.map(article => <Article key={article.id} article={article} handleChange={handleChange}/>)}
</ul>
</>
)
My custom hook to fetch data:
export function useHttp<T>(initUrl: string, initData: T): UseHttp<T> {
const initOptions: AxiosRequestConfig = { url: initUrl };
const [options, setOptions] = useState(initOptions);
const useHttpReducer = createHttpReducer<T>();
const [state, dispatch] = useReducer(useHttpReducer, {
isLoading: false,
error: '',
data: initData
});
useEffect(() => {
let cancelRequest = false;
const fetchData = async (cancelRequest: boolean = false) => {
if (!options.url) return;
dispatch({ type: API_REQUEST});
try {
const responsePromise: AxiosPromise<T> = axios(options);
const response = await responsePromise;
if (cancelRequest) return;
dispatch({ type: API_SUCCESS, payload: response.data });
} catch (e) {
console.log("Got error", e);
dispatch({ type: API_ERROR, payload: e.message });
}
};
fetchData(cancelRequest);
return () => {
cancelRequest = true;
}
}, [options]);
const executeFetch = (url: string, options: AxiosRequestConfig = axiosInitialOptions): void => {
options.url = url;
setOptions(options);
};
return { ...state, executeFetch}
The issue is, when I'm doing something like this, the data replaces to the new response (of the POST request), then my UI crashes (no more article list..)
What's the good practice to manage situations like this when I need to call another API in the same component while keeping the reusability of my HTTP hook?
I simply want to execute a POST request somewhere in the component after my GET one - How I can do it in a reusable way and fix my issue?
You can refactoring your custom hook to receive a callback function. I omitted the part of cancelRequest, if you are using axios you can cancel the request via CancelToken:
export function useHttp<T>(initUrl: string): UseHttp<T> {
const initOptions: AxiosRequestConfig = { url: initUrl };
const [options, setOptions] = useState(initOptions);
const useHttpReducer = createHttpReducer<T>();
const [state, dispatch] = useReducer(useHttpReducer, {
isLoading: false,
error: '',
});
const fetchData = async (options, callback) => {
if (!options.url) return;
dispatch({ type: API_REQUEST});
try {
const responsePromise: AxiosPromise<T> = axios(options);
const response = await responsePromise;
dispatch({ type: API_SUCCESS, payload: response.data });
callback(response.data);
} catch (e) {
console.log("Got error", e);
dispatch({ type: API_ERROR, payload: e.message });
}
};
const executeFetch = (url: string, requestOptions: AxiosRequestConfig = axiosInitialOptions, callback): void => {
options.url = url;
fetchData({...options, ...requestOptions}, callback);
};
return { ...state, executeFetch}
};
Usage:
const [articles, setArticles]= useState();
const { error, isLoading, executeFetch } = useHttpRequest();
const handleChange = (article: IArticle, event: React.ChangeEvent<HTMLInputElement>) => {
executeFetch(`updateNews?id=${article.id}`, { method: 'post', data: { isRead: event.target.checked }}, setArticles);
};

axios GET Request constantly running

I am working on my React application and noticed an error. When I console log the code below, the GET request from my Express back end, the console log runs without stopping.
api-helper.js (REACT)
export const getAllPages = async () => {
getToken();
const resp = await api.get(`pages/`);
console.log('><><><><><><><>< return getAllPages response ><><><><><><><><',resp) //
const parsedResponse = resp.data.map((page) => ({
...page,
siteName: page.siteUniqueName?.split("-")[1],
}));
return parsedResponse;
};
pageRouter.js (express)
pageRouter.get("/", restrict, async (req, res, next) => {
try {
const { user } = req;
const pages = await Page.findAll({
where: {
userId: user.id
},
include: [
{ model: Site },
{ model: VisitRecord },
{ model: Lead }
]
});
res.json(pages);
} catch (e) {
next(e);
}
});
This would obviously be bad in production if it were making calls on a live database. How do I get this to stop this get running constantly in the background?
Update:
This is the code on the dashboard that calls the API where all pages are rendered:
Dashboard.jsx
useEffect(() => {
props.getAllPages();
}, []);
App.js
getAllUserPages = async () => {
// console.log('called here1')
const pages = await getAllPages();
if (pages) {
this.setState({
sites: pages,
});
}
};
async componentDidMount() {
// console.log('called________')
const currentUser = await getCurrentUser();
if (currentUser) {
const preservedSites = await getAllPages();
this.setState({
currentUser,
preservedSites: preservedSites.map((site) => site.siteName),
});
} else {
if (
!(
this.props.history.location.pathname.startsWith("/reset/") ||
this.props.history.location.pathname === "/" ||
matchPath(this.props.history.location.pathname, {
path: "/:userId/:siteName",
exact: false,
strict: false,
})
)
) {
this.props.history.push("/auth");
}
}
const pages = await getAllPages();
if (pages) {
this.setState({
sites: pages,
});
}
const resp = await api.get("/users");
const users = resp.data;
this.setState({
users: users,
});
}

Categories

Resources