In the backend I am processing the data and then sending it to React through JSON. Here is the code.
res.setHeader('Content-Type', 'application/json');
var obj = {field: current, fieldCnt: cnt }
var obj2 = JSON.stringify(obj)
res.write(obj2);
var obj3 = {length: currentcnt, field2: current, fieldCnt2: cnt }
var obj4 = JSON.stringify(obj3)
res.end(obj4);
The backend I showed here is not the same as it is. I just showed it as an example. I had to use res.write and res.end because I had to collect data for different if conditions.
Below here is the code in react where I am getting this data through Axios.
var data2 = axios.get('http://localhost:5000/get').then(res => {
console.log(res.data) //Check the Attached Chrome Developers console image.
return res.data
});
const data3 = data2.length //This isn't working (length can be seen the console image last line "length" : 18)
Chrome Developers console image
Please tell me how to solve this with React Hooks. I think it has to be done with mapping but i don't how.
As #Tobias Geiselmann said axios.get() returns a promise, and you're assigning the length of the promise.
If you return a value from .then(), the next then() is called with that value.
After looking at your screenshot. It looks like you're trying to access the length property from the data return by your API. I would recommend structuring your API response like so
{
count: 18,
results: [
{ key: 'val' },
{ key: 'val' },
{ key: 'val' },
]
}
By doing so you'll be to access the length with:
res.data.count // will have the count
res.data.results // will have all the results
Try this
axios.get('http://localhost:5000/get').then((res) => {
console.log(res.data.length); // will print the length
});
another example:
const data2 = axios.get('http://localhost:5000/get')
.then((data) => {
return data;
});
data2.then(data => {
console.log(data.length) // will print the length
})
example with async/await
const myFunc = async () => {
const { data } = await axios.get('http://localhost:5000/get');
console.log(data.length); // will print the length
};
To solve this with hooks you can fetch data when the component loads with useEffect hook and store it inside useState hook.
const [data, setData] = useState([])
useEffect(() => {
axios.get('http://localhost:5000/get').then(res => setData(res.data))
}, [])
const data3 = data.length
Related
the main problem is that when I console.log "datasource" array it first shows that array populated the way I want to, which is:
[
0:{ date: date, value: value },
1:{ date: date, value: value },
...
]
but then after the first log loads it suddenly changes to a empty array [];
Here is my code:
import React, {useState, useEffect} from 'react'
import { ChartComponent, LineSeries, ColumnSeries, SeriesDirective, SeriesCollectionDirective, Inject } from '#syncfusion/ej2-react-charts'
import axios from 'axios'
const StablesTVLchart = () => {
const [stables, setStables] = useState([])
const dates = new Array;
const totalCirculating = new Array;
const totalPegged = new Array;
const datasource = new Array;
useEffect(() => {
axios.get('https://stablecoins.llama.fi/stablecoincharts/all?stablecoin=1')
.then(res => {
setStables(res.data)
// Populate dates array and totalCirculating array /
for (var i = 0; i < stables.length; i++){
dates.push(parseFloat(stables[i].date))
totalCirculating.push(data[i].totalCirculatingUSD)
}
// Populate totalPegged array /
for (var y = 0; y < totalCirculating.length; y++){
totalPegged.push(totalCirculating[y].peggedUSD)
}
// Populate datasource array with date and totalPegged /
for (var e = 0; e < datadate.length; e++){
datasource.push({ date: dates[e], value: totalPegged[e] })
}
})
.catch(err => {
console.log(err)
})
}, []);
console.log(datasource);
const primaryxAxis = {visible: false }
const primaryyAxis = { labelFormat: '${value}K', visible: false }
const palette = ["skyblue"]
return (
<div className="w-full">
<ChartComponent id="charts" primaryXAxis={primaryxAxis} primaryYAxis={primaryyAxis} palettes= {palette}>
<Inject services={[ColumnSeries, LineSeries]} />
<SeriesCollectionDirective>
<SeriesDirective dataSource={datasource} xName='date' yName='value' name='TVL'/>
</SeriesCollectionDirective>
</ChartComponent>
</div>
)
}
export default StablesTVLchart
I recon that its possible I need to somehow make this datasource array into a state array?
If anyone has any clues or an idea on how to do this, I'd be very grateful.
As it appears from the code you provided that you are using state to store the data, but immediately trying to use it, I will remind you that React may batch multiple setState() calls into a single update for performance.
Also for improvement of the code readability, you can use something like:
useEffect(() => {
axios.get('https://stablecoins.llama.fi/stablecoincharts/all?stablecoin=1')
.then(res => {
const stables = res.data;
const dates = stables.map(item => parseFloat(item.date));
const totalCirculating = stables.map(item => item.totalCirculatingUSD);
const totalPegged = totalCirculating.map(item => item.peggedUSD);
const datasource = totalPegged.map((value, index) => ({ date: dates[index], value }));
setStables(datasource);
})
.catch(err => {
console.log(err)
});
}, []);
The api returns a single array. You store the api's response in a state you don't use. You then store parts of the data of original response in 4 arrays by mutating them (using push). You try to use one of the mutated arrays (datasource) in the view, but as soon as the view is re-rendered (because of setStables(res.data)) the array is re-created with an empty array. In addition, updating a variable/constant asynchronously, and mutating the arrays doesn't cause a re-render, and even if it would react won't detect the change, and won't change the view.
Solution:
Use Array.map() to create a new array based on the api's response array
Store result of the map into the state, and use that state in your view
Example:
const StablesTVLchart = () => {
const [datasource, setDatasource] = useState([])
useEffect(() => {
axios.get('https://stablecoins.llama.fi/stablecoincharts/all?stablecoin=1')
.then(({ data }) => {
setDatasource(data.map(({ date, totalCirculatingUSD }) => ({
date: parseFloat(date),
value: totalCirculatingUSD.peggedUSD
})))
})
.catch(err => {
console.log(err)
})
}, []);
console.log(datasource);
}
I have a problem with dynamic routing in next 13, I have dynamic page [id].js and trying to fetch the data
const res = await fetch(`myAPI`);
const resData = await res.json();
const paths = resData.data.map((r) => ({
params: { id: r.id}
}));
return {
paths,
fallback: false
}
It does not work and gives me error with .map function, if I hard code the path it works without any issue and give me correct output data
Hard coded example:
paths: [
{params: { id: '67'}}
],
I know that my map function should be correct as I tested in inside the component
axios
.get(`myAPI`)
.then((response) => {
console.log(response.data.map((res) => {return(res.id)}))
})
console output in component return data without complaining, why I cannot achieve it in getStaticPath?
resData is already your array of objects, so you can "skip" data:
const res = await fetch(`myAPI`);
const resData = await res.json();
const paths = resData.map((r) => ({
params: { id: r.id}
}));
The reason why when using Axios you have to use data, is because Axios already gets the response data as JSON for you (as data). You were confusing Axios' response for resData.
I have a Next.js application here which needs to read a CSV file from a URL in the same repo in multiple places, but I cannot seem to be able to retrieve this data. You can find the relevant file in my repo here.
Note, the URL I'm trying to pull data from is this: https://raw.githubusercontent.com/ivan-rivera/balderdash-next/main/public/test_rare_words.csv
Here is what I've tried so far:
Approach 1: importing the data
let vocab = {};
...
async function buildVocab() {
const words = await import(VOCAB_URL); // this works when I point to a folder in my directory, but it does not work when I deploy this app. If I point at the URL address, I get an error saying that it cannot find the module
for (let i = 0; i < words.length; i++) {
vocab[words[i].word] = words[i].definition;
}
}
Approach 2: papaparse
const papa = require("papaparse");
let vocab = {};
...
export async function buildVocab() {
await papa.parse(
VOCAB_URL,
{
header: true,
download: true,
delimiter: ",",
step: function (row) {
console.log("Row:", row.data); // this prints data correctly
},
complete: function (results) {
console.log(results); // this returns an object with several attributes among which is "data" and "errors" and both are empty
},
}
);
// this does not work because `complete` does not return anything
vocab = Object.assign({}, ...raw.map((e) => ({ [e.word]: e.definition })));
console.log(vocab);
}
Approach 3: needle
const csvParser = require("csv-parser");
const needle = require("needle");
let vocab = {};
...
let result = [];
needle
.get(VOCAB_URL)
.pipe(csvParser())
.on("data", (data) => {
result.push(data);
});
vocab = Object.assign({}, ...result.map((e) => ({ [e.word]: e.definition })));
// This approach also returns nothing, however, I noticed that if I force it to sleep, then I do get the results I want:
setTimeout(() => {
console.log(result);
}, 1000); // now this prints the data I'm looking for
What I cannot figure out is how to force this function to wait for needle to retrieve the data. I've declared it as an async function and I'm calling it with await buildVocab() but it doesn't help.
Any ideas how I can fix this? Sorry, I'm a JS beginner, so it's probably something fundamental that I'm missing :(
After spending hours on this, I think I finally found a solution:
let vocab = {};
export async function buildVocab() {
await fetch(VOCAB_URL)
.then((resp) => resp.text())
.then((text) => {
papa.parse(text, { header: true }).data.forEach((row) => {
vocab[row.word] = row.definition;
});
});
}
The only oddity that I still can't work out is this: I'm calling my buildVocab function inside another async function and I noticed that if I do not include a console.log statement in that function, then the vocab still does not get populated in time. Here is the function:
export async function sampleWord() {
await buildVocab();
const keys = Object.keys(vocab);
const index = Math.floor(Math.random() * keys.length);
console.log(`selected word: ${keys[index]}`); // this is important!
return keys[index];
}
I am completely new to react.js.
I am fetching async data from my server that uses express.js. After I get that data I want to set my house parameters when I open that page for the first time.
const Houses = () => {
const [house, setHouse] = useState({});
...
useEffect(() => {
const fetchData = () => {
fetch('http://localhost:9000/houses')
.then(res => res.text())
.then(res => {
if (res) {
let houseData = JSON.parse(res);
console.log(houseData); // server res prints correctly - prints: { name: 'sweet house', address: 'fukuoka hakata' }
setHouse({...house, houseData});
console.log(house); // doesnt change after sethouse - prints : {}
}
});
}
fetchData();
}, []);
...
}
Im getting the data from my server without any problem.
The problem is that the house parameters dont get updated. I know its a different scope, what I need to know is how I do it in this case. Thanks
You cannot access the house state immediately after setting it, setHouse may be batched.
See more of State: https://reactjs.org/docs/state-and-lifecycle.html
You are trying to do
let houseData = JSON.parse(res);
// houseData = { name: 'sweet house', address: 'fukuoka hakata' }
setHouse({ ...house, houseData: houseData });
instead of setHouse(houseData). Since houseData is an Object, you can directly set it.
Replace
setHouse({...house, houseData})
with
setHouse(houseData)
I have a three-check box type,
When I check any box I call refetch() in useEffect().
The first time, I check all boxes and that returns the expected data!
but for some cases "rechange the checkboxes randomly", the returned data from API is "undefined" although it returns the expected data in Postman!
So I Guess should I need to provide a unique queryKey for every data that I want to fetch
so I provide a random value "Date.now()" but still return undefined
Code snippet
type bodyQuery = {
product_id: number;
values: {};
};
const [fetch, setFetch] = useState<number>();
const [bodyQuery, setBodyQuery] = useState<bodyQuery>({
product_id: item.id,
values: {},
});
const {
data: updatedPrice,
status,
isFetching: loadingPrice,
refetch,
} = useQuery(
['getUpdatedPrice', fetch, bodyQuery],
() => getOptionsPrice(bodyQuery),
{
enabled: false,
},
);
console.log('#bodyQuery: ', bodyQuery);
console.log('#status: ', status);
console.log('#updatedPrice: ', updatedPrice);
useEffect(() => {
if (Object.keys(bodyQuery.values).length > 0) {
refetch();
}
}, [bodyQuery, refetch]);
export const getOptionsPrice = async (body: object) => {
try {
let response = await API.post('/filter/product/price', body);
return response.data?.detail?.price;
} catch (error) {
throw new Error(error);
}
};
So after some elaboration in the chat, this problem can be solved by leveraging the useQuery key array.
Since it behaves like the dependency array in the useEffect for example, everything that defines the resulted data should be inserted into it. Instead of triggering refetch to update the data.
Here the key could look like this: ['getUpdatedPrice', item.id, ...Object.keys(bodyQuery.values)], which will trigger a new fetch if those values change and on initial render.