How to return string value? - reactjs

I wrote this code
const link = "CKV0nSlxV8M"
const rendertest = async (link) => {
const format = await ytdl(link, { quality: '22'})
let test = JSON.stringify(format[0].url)
alert(test) //string type
return test
}
let finalValue = rendertest(link)
console.log(finalValue)
And I got this value from the test (string)
but exam value is not a String (Object)
I don't know which part I wrote wrong. I want the output of the same test and finalValue

When you define a function as async, behind the scenes it returns a promise. So, you have to wait for the promise to fulfill. Try this:
const link = "CKV0nSlxV8M"
const rendertest = async (link) => {
const format = await ytdl(link, { quality: '22'});
const test = JSON.stringify(format[0].url);
return test
}
rendertest(link).then(finalValue => {
console.log(finalValue)
}

Related

Is TypeScript linter being overly cautious?

I'm getting a warning from my linter about something in this function:
React.useEffect(() => {
const uploadFiles = async (fileList: FileList) => {
const uploadSessionId = getUUID();
let mediaSetId: string | null = null;
await getMediaSetId().then(response => {mediaSetId = response});
for (let i = 0; i < fileList.length; i++) {
const file: File = fileList[i];
const originalFilename = file.name;
const fileExtension = originalFilename.split('.').pop() ?? 'unknown';
await getBase64(file).then(result => uploadFile(result, originalFilename, fileExtension, file.lastModified, mediaSetId, uploadSessionId));
}
};
if (isUploading && fileList) {
// Start the upload process
uploadFiles(fileList);
}
}, [isUploading, fileList]);
The exact error message is: Function declared in a loop contains unsafe references to variable(s) 'mediaSetId'
When building it, I first thought about putting the for loop within the .then clause but chose to do it as above, whereby I instantiate mediaSetId = null and then the async function call populates it accordingly.
Is this approach I've used "wrong"? It all seems to be working as expected by the way.

Why doesn't the parser wait for Promise.resolve?

I am using React and I do not understand why in the useEffect when running a map function the second part of the code runs before the first part (which is a promise resolve).
Shouldn't the parser wait for the promise to resolve and then run the second part of the code?
useEffect(() => {
const pools = mainnet.Exchanges.Pancakeswap.LpTokens.map((lpPool) => {
// part 1
const [tokenZeroSymbol, tokenOneSymbol] = lpPool.name.replace(' LP', '').split('-');
const prices = fetchTokenPrice(tokenZeroSymbol.toLowerCase(), tokenOneSymbol.toLowerCase());
Promise.resolve(prices).then((values) => {
const [priceTokenZero, priceTokenOne] = values;
filteredFarmPools.find((pool) => {
if (lpPool.name.replace(' LP', '') === pool.name) {
pool.priceTokenZero = values[0].usd;
pool.priceTokenOne = values[1].usd;
}
console.log('inside the fethcprice promise');
});
});
// part 2
filteredFarmPools.find((pool) => {
if (lpPool.name.replace(' LP', '') === pool.name) {
const tvl0 = (pool.reserveTokenZero / 10 ** 18) * pool.priceTokenZero;
const tvl1 = (pool.reserveTokenOne / 10 ** 18) * pool.priceTokenOne;
pool.tvl = tvl0 + tvl1;
}
console.log('inside the tvl calc');
});
});
No.
Promises give you an object that you can pass around and call then on.
They do not turn asynchronous code into blocking code.
The second part of the code isn't inside the then callback so it runs while the asynchronous code (that will trigger the first promise to resolve) is running in the background.
That said, see the await keyword for asyntax that can give the illusion that a promise is blocking.
useEffect(() => {
const processPools = async () => {
for (let lpPool of mainnet.Exchanges.Pancakeswap.LpTokens) {
const [tokenZeroSymbol, tokenOneSymbol] = lpPool.name.replace(' LP', '').split('-');
const values = await fetchTokenPrice(tokenZeroSymbol.toLowerCase(), tokenOneSymbol.toLowerCase());
// Promise.resolve(prices).then((values) => {
const [priceTokenZero, priceTokenOne] = values;
filteredFarmPools.find((pool) => {
if (lpPool.name.replace(' LP', '') === pool.name) {
pool.priceTokenZero = values[0].usd;
pool.priceTokenOne = values[1].usd;
}
console.log('inside the fethcprice promise');
// });
});
}
}
processPools();
});
Original Array.map does not support async
Promise.resolve return immediately, no difference with Promise.then

wait for array to be filled using .push in react?

I am fetching an api and pushing results to an empty array, but I need the array to be filled to display the information within the array. I am getting "cannot read property high of undefined" i'm assuming because the array is not filled before rendering, how can I wait for the for loop to be complete before rendering the page?
function TopStocks(props) {
const symbols = ["AAPL", "NFLX", "GOOGL", "TSLA"];
const stockInfo = [];
useEffect(() => {
fetchSymbols();
}, []);
async function fetchSymbols() {
for (let i = 0; i < symbols.length; i++) {
await fetch(
`api&symbol=${symbols[i]}`
)
.then((res) => res.json())
.then((allStocks) => {
try {
let metaDataEntries = allStocks["Meta Data"];
let symbol = metaDataEntries["2. Symbol"].toUpperCase();
let pastDataEntries = allStocks["Time Series (Daily)"];
let pastDataValues = Object.values(pastDataEntries);
let mostRecentValue = pastDataValues[0];
let x = Object.values(mostRecentValue);
let open = parseFloat(x[0]).toFixed(2);
let high = parseFloat(x[1]).toFixed(2);
let low = parseFloat(x[2]).toFixed(2);
let close = parseFloat(x[3]).toFixed(2);
let percentage = close - open;
let result = parseFloat(percentage).toFixed(2);
stockInfo.push({
symbol: symbol,
high: high,
low: low,
close: close,
open: open,
percentage: result,
});
} catch {
console.log("surpassed the limit of 4 requests in under a minute");
}
});
}
}
return (<span className="header__grid-price">{stockInfo[0].high}</span>)
}
You are doing a simple push operation on stockInfo, which will not trigger the rerender, for that, you have to change the state of it, use useState hooks instead,
import React, { useEffect, useState } from "react";
function TopStocks(props) {
const symbols = ["AAPL", "NFLX", "GOOGL", "TSLA"];
const [stockInfo, setStockInfo] = useState([]);
useEffect(() => {
fetchSymbols();
}, []);
async function fetchSymbols() {
for (let i = 0; i < symbols.length; i++) {
await fetch(`api&symbol=${symbols[i]}`)
.then((res) => res.json())
.then((allStocks) => {
try {
let metaDataEntries = allStocks["Meta Data"];
let symbol = metaDataEntries["2. Symbol"].toUpperCase();
let pastDataEntries = allStocks["Time Series (Daily)"];
let pastDataValues = Object.values(pastDataEntries);
let mostRecentValue = pastDataValues[0];
let x = Object.values(mostRecentValue);
let open = parseFloat(x[0]).toFixed(2);
let high = parseFloat(x[1]).toFixed(2);
let low = parseFloat(x[2]).toFixed(2);
let close = parseFloat(x[3]).toFixed(2);
let percentage = close - open;
let result = parseFloat(percentage).toFixed(2);
let temp = [...stockInfo];
temp.push({
symbol: symbol,
high: high,
low: low,
close: close,
open: open,
percentage: result
});
setStockInfo(temp);
} catch {
console.log("surpassed the limit of 4 requests in under a minute");
}
});
}
}
return (
<span className="header__grid-price">
{stockInfo[0].high ? stockInfo[0].high : "loading"}
</span>
);
}
You are correct in your assumption. Try using the map function as it is async along with Promise.all so that you block the return of that function until all of your calls have finished.
...
Promise.all(
symbols.map(symbol => {
fetch(`api&symbol=${symbol}`)
.then(
// whatever you want to do with it
)
})
);
React hates it when you mutate constants. It's better to use the useState method to create the constant and the setter method.
const [stockInfo, setStockInfo] = useState([]); //This will default stockInfo to an empty array.
Then make your response dump into an array and setStockInfo() that array.
ex:
let newStockInfo = [];
/* Your stock gathering function here, but dumps into newStockInfo */
setStockInfo(newStockInfo);
That will update your stocks and prevent undefined properties.
I'm sure there is another way to do this, but this is a pretty quick way to get it done.

Execute .Then() promise NodeJS

I am trying to figure out how to call a Promise using ".then" so I can continue performing other functions on the return Promise output. I have confirmed the function being used works as expected, but after watching videos and other SO examples am still having a hard time getting this working. See below snippet:
const fs = require('fs');
const JSZip = require('jszip');
const directoryFile = fs.readdirSync('./zipped');
//console.log(directoryFile);
var zip = new JSZip();
var dir = ('./zipped/');
const readZip = async () => {
const promiseToken = new Promise((resolve, reject) => {
fs.readFile((dir + directoryFile), function (err, data) {
if (err) throw err;
JSZip.loadAsync(data).then(function (zip) {
const files = Object.keys(zip.files);
console.log(files);
files.forEach((files) => {
const pkgName = files.substring(files.indexOf("_", files.indexOf("_")) + 1, files.lastIndexOf("_"));
const fileExt = files.split('.').pop();
const pkgExtract = (pkgName + "." + fileExt);
});
})
});
return promiseToken;
});
};
console.log('Program Starts');
readZip().then((promiseToken) => {
console.log(promiseToken.join(','));
});
console.log('Program Ends');
I keep getting "(node:1144376) UnhandledPromiseRejectionWarning: ReferenceError: Cannot access 'promiseToken' before initialization" The above code block take an array of file names and loops through each element and extracts portions of the file name and joins the portions of each elements name that I need to create a new file name. Again, the function works and is tested. What is not working is when I try to call the return output of "readZip()" via ".then()". I need to do get this portion working so I can continue on with the rest of the script. I am new to NodeJS and Javascript and any assistance would be appreciated as none of the videos or examples I have attempted seem to be working.....
You seem to have missed a line, and are returning promiseToken from the promise's constructor instead of from the definition of readZip. Therefore, readZip returns nothing, and you get an undefined value.
Move it to the correct place and you should be fine:
const readZip = async () => {
const promiseToken = new Promise((resolve, reject) => {
fs.readFile((dir + directoryFile), function (err, data) {
if (err) throw err;
JSZip.loadAsync(data).then(function (zip) {
const files = Object.keys(zip.files);
console.log(files);
files.forEach((files) => {
const pkgName = files.substring(files.indexOf("_", files.indexOf("_")) + 1, files.lastIndexOf("_"));
const fileExt = files.split('.').pop();
const pkgExtract = (pkgName + "." + fileExt);
});
})
});
});
return promiseToken; // Moved here
};
You need to:
return the promise in your readZip function (currently you are not doing that)
resolve the promise with your desired data (currently you are not resolving at all)
Use that data in the .then like so:
readZip().then((data) => {
// Use the data to do whatever you want
});
This can be a lot simpler if you use the fs.promises interface where fs.promises.readfile() is already a version that returns a promise:
const readZip = async () => {
const data = await fs.promises.readFile(dir + directoryFile);
const zip = await JSZip.loadAsync(data);
const files = Object.keys(zip.files);
console.log(files);
return files;
};
readZip.then(files => {
for (file of files) {
const pkgName = file.substring(file.indexOf("_", file.indexOf("_")) + 1, file.lastIndexOf("_"));
const fileExt = file.split('.').pop();
const pkgExtract = pkgName + "." + fileExt;
console.log(pkgExtract);
}
})

how to set state in react componentDidMount with method?

code is like this:
componentDidMount() {
this.setState(({getPublicTodosLength}, props) => ({
getPublicTodosLength: () => this.getPublicTodosLengthForPagination() // no returned value
}));
}
getPublicTodosLengthForPagination = async () => { // get publicTodos length since we cannot get it declared on createPaginationContainer
const getPublicTodosLengthQueryText = `
query TodoListHomeQuery {# filename+Query
viewer {
publicTodos {
edges {
node {
id
}
}
}
}
}`
const getPublicTodosLengthQuery = { text: getPublicTodosLengthQueryText }
const result = await this.props.relay.environment._network.fetch(getPublicTodosLengthQuery, {})
return result.data.viewer.publicTodos.edges.length;
}
getPublicTodosLengthForPagination is not invoked and the returned value is not assigned.Also, When i invoke it right away e.g. without () => it's assigned value is a promise? I am expecting int/number, the return value of edges.length. help?
The returned value is not assigned because you are not invoking the function rather assigning it.
componentDidMount() {
this.setState(({getPublicTodosLength}, props) => ({
getPublicTodosLength: this.getPublicTodosLengthForPagination()
}));
}
I'm not sure why you're setting state like that, maybe you could help explain what you're doing. In the meantime shouldn't it be written like this:
componentDidMount() {
this.setState({
getPublicTodosLength: await this.getPublicTodosLengthForPagination() // no returned value
});
}
getPublicTodosLengthForPagination = async () => { // get publicTodos length since we cannot get it declared on createPaginationContainer
const getPublicTodosLengthQueryText = `
query TodoListHomeQuery {# filename+Query
viewer {
publicTodos {
edges {
node {
id
}
}
}
}
}`
const getPublicTodosLengthQuery = { text: getPublicTodosLengthQueryText }
const result = await this.props.relay.environment._network.fetch(getPublicTodosLengthQuery, {})
return result.data.viewer.publicTodos.edges.length;
}

Resources