Accessing nested JSON object in React - javascript

Dataset: https://disease.sh/v3/covid-19/historical/usa?lastdays=all
I am newer to React and am trying to get my feet wet with a COVID-19 Tracker so bear with me... I am trying to access Timeline > Cases from the above dataset but can't seem to make it work. I've tried let date in data.timeline.cases however that doesn't work either. Maybe i'm looking in the wrong spot - looking for some guidance. Thanks!
const buildChartData = (data, casesType) => {
let chartData = [];
let lastDataPoint;
for (let date in data.cases) {
if (lastDataPoint) {
let newDataPoint = {
x: date,
y: data[casesType][date] - lastDataPoint,
}
chartData.push(newDataPoint);
}
lastDataPoint = data[casesType][date];
}
return chartData;
};
function LineGraph({ casesType = 'cases' }) {
const [data, setData] = useState({});
useEffect(() => {
const fetchData = async() => {
await fetch('https://disease.sh/v3/covid-19/historical/usa?lastdays=120')
.then((response) => {
return response.json()
})
.then(data => {
let chartData = buildChartData(data, casesType);
setData(chartData);
});
};
fetchData();
}, [casesType]);

Ok, as you said you tried with let date in data.timeline.cases
but you need to change the other part of code too.
It s not data[casesType] but data.timeline[casesType]
for (let date in data.timeline.cases) {
if (lastDataPoint) {
let newDataPoint = {
x: date,
y: data.timeline[casesType][date] - lastDataPoint,
}
chartData.push(newDataPoint);
}
lastDataPoint = data.timeline[casesType][date];
}

Related

How to get each item from a filtered array, without using a map for each item

I'm taking an array and filtering the value in a context:
const { responsible } = useResponsible()
const [ids, setIds] = useState([])
const filteredResponsible = responsible?.filter((resp) =>
ids.includes(resp.id)
)
The problem is that I need to make a map to get the corresponding value of each id, one by one. This ends up making the code too long:
const { filteredResponsible } = useResponsible
const responsibleName = filteredResponsible.map((resp) => resp.name)
const responsibleEmail = filteredResponsible.map((resp) => resp.email)
const responsibleAddress = filteredResponsible.map((resp) => resp.address)
...
And so on with each item in the array.
I'm using the React Hook Form's setValue to set the value in the inputs:
useEffect(() => {
setValue('name', `${responsibleName}`)
setValue('email', `${responsibleEmail}`)
setValue('address', `${responsibleAddress}`)
setValue('cep', `${responsibleCep}`)
setValue('district', `${responsibleDistrict}`)
setValue('city', `${responsibleCity}`)
setValue('state', `${responsibleState}`)
setValue('phone', `${responsiblePhone}`)
setValue('sex', `${responsibleSex}`)
}, [])
How can I make these maps smaller? Without having to make a map to get each item in the array?
There doesn't seem to be any reason to do those map calls on every render and to do them anywhere other than where you need them, since you only show using the result in a mount-only effect. Just do them there:
const { filteredResponsible } = useResponsible; // Is there really no `()` needed here?
useEffect(() => {
setValue("name", `${filteredResponsible.map(({name}) => name)}`);
setValue("email", `${filteredResponsible.map(({email}) => email)}`);
setValue("address", `${filteredResponsible.map(({address}) => address)}`);
// ...
}, []);
If you really need those distinct arrays on every render, unless you can change your data structures to be more amenable to your output I don't see you have a lot of options. You can at least avoid multiple loops through filteredResponsible:
const { filteredResponsible } = useResponsible; // ()?
const responsibleName = [];
const responsibleEmail = [];
const responsibleAddress = [];
for (const { name, email, address } of filteredResponsible) {
responsibleName.push(name);
responsibleEmail.push(email);
responsibleAddress.push(address);
}
And if that's really the case, you may want to avoid doing it on every render:
const { filteredResponsible } = useResponsible; // ()?
const { responsibleName, responsibleEmail, responsibleAddress } = useMemo(() => {
const responsibleName = [];
const responsibleEmail = [];
const responsibleAddress = [];
for (const { name, email, address } of filteredResponsible) {
responsibleName.push(name);
responsibleEmail.push(email);
responsibleAddress.push(address);
}
return { responsibleName, responsibleEmail, responsibleAddress };
}, [filteredResponsible]);

Why the default value variable change as the changed variable value, Vuejs

as you see the code, on the handleUpdateFilter function the second "if" some how defaultCourseData is filtered as filteredData of the first "if". Thank you for helping me!
setup() {
const course = ref();
const defaultCourseData = null
const gettingCourse = async () => {
const { data } = await getCourse();
defaultCourseData = data
course.value = data;
};
const handleUpdateFilter = (data) => {
// data is filtering value
if (data.value.view) {
const filteredData = defaultCourseData.sort((a, b) => b.luotXem - a.luotXem);
course.value = filteredData;
}
if (!data.value.view) {
course.value = defaultCourseData // This case some how defaultCourseData filtered too
}
};
onMounted(() => {
gettingCourse();
});
return {
course,
handleUpdateFilter,
defaultCourseData
};
},
Your defaultCourseData variable isn't reactive.
Therefore it should be evaluated as null at every call.
Try this
defineComponent({
setup() {
const course = ref([]);
const defaultCourseData = ref([]);
const gettingCourse = async () => {
const { data } = await getCourse();
defaultCourseData.value = data
course.value = data;
};
const handleUpdateFilter = (data) => {
// data is filtering value
if (data.value.view) {
course.value = defaultCourseData.value.sort((a, b) => b.luotXem - a.luotXem);
}
if (!data.value.view) {
course.value = defaultCourseData.value // This case some how defaultCourseData filtered too
}
};
onMounted(async () => {
await gettingCourse();
});
return {
course,
handleUpdateFilter,
defaultCourseData
};
})
Edit: The actual issue here was, that the defaultCourseData always returned a sorted array as Array.prototype.sort() mutates the Array.
So making a copy solves the issue.
if (data.value.view) { course.value = [...defaultCourseData.value].sort((a, b) => b.luotXem - a.luotXem); }

Transform API data and fetching every 60 seconds [react]

Hi I'm currently having problems with formatting data I'm receiving from an API
Should I use reduce instead of forEach?
Here is the desired output, an array of objects with just the titles and prices:
[
{
title: "Meter",
price:"9.99"
},
{
title: "Plan One",
price:"11.99"
}
]
Here is how I am getting the data, setting it, refetching it every 60 seconds:
const [products, setProducts] = useState([]);
const formatProduct = (products) =>{
let result = [];
products.forEach((product)=>{
if(product.variants['price'] !== "0.00"){
result.push({product["title"],product.variants[0]["price"]})
}
})
return result
}
useEffect(() => {
const fetchData = async () => {
const axiosResponse = await axios(`https://www.today/products.json`);
setProducts(formatProduct(axiosResponse.data.products));
};
const reFetchData = setInterval(() => setProducts(fetchData()), 60000);
return () => {
clearInterval(reFetchData);
};
}, []);
Adding object to the result array you have to specify the name of props. Also you've missed index of variants when you compare a price:
const formatProduct = (products) =>{
let result = [];
products.forEach((product)=>{
if(product.variants[0]['price'] !== "0.00"){ //index 0
result.push({
title: product["title"], // specify the prop name
price: product.variants[0]["price"]
})
}
})
return result
}
There is another problem in your code. What happens if variant doesn't contain any item? I would check array length and use filter and map functions:
const formatProduct = (products) => {
return products
.filter(p => p.variants.lenght>0 && p.variants[0]!=="0.00")
.map(p => {title: p.title, price: p.variants[0].price});
}
Another problem is how you call setProducts(fetchData()) in the interval function. You shouldn't call setProducts() because you're already calling it in fetchData(). So it has to be:
const reFetchData = setInterval(() => fetchData(), 60000);

How to compare day in js

export const fetchDailyData = async () => {
try {
const { data } = await axios.get(`${url}/daily`);
let today = new Date('2020-01-27');
let referanceDay = new Date(dailyData.reportDate)
const modifiedData = data.map((dailyData) => ({
if(referanceDay => today){
confirmed: dailyData.confirmed.total,
deaths: dailyData.deaths.total,
date: dailyData.reportDate
};
}))
// return modifiedData
} catch (error) {
}
}
I am trying to compare days and return proper ones. But it's not worked. I think I got a mistake object and if section. Could you please look my problem. Thanks..
Daily data is argument to anon. Function but being referenced out in which case it would be undefined.
It looks like your >= comparison in your if statement is backwards. Also you are referencing dailyData before it is declared inside mapTry this:
export const fetchDailyData = async () => {
try {
const { data } = await axios.get(`${url}/daily`);
let today = new Date('2020-01-27');
const modifiedData = data.map((dailyData) => ({
let referanceDay = new Date(dailyData.reportDate)
if(referanceDay >= today){
confirmed: dailyData.confirmed.total,
deaths: dailyData.deaths.total,
date: dailyData.reportDate
};
}))
// return modifiedData
} catch (error) {
}
}
I think you should use a library to compare the dates. I use Moment.js for all my datetime operations.
enter link description here
example from docs :
moment('2010-10-20').isAfter('2010-01-01', 'year'); // false

undefined after setState() (use hook) in Reactjs

I learn react and js myself. please explain why this situation occurs. PS: excuse me for the large text, I tried to explain the problem as clearly as possible. thanks. Essence of the matter: set the initial state through the hook:
const [pokemon, setPokemon] = useState({
img: "",
name: "",
types: [],
abilities: [],
moveList: [],
weight: "",
height: "",
description: "",
genus: "",
chanceToCatch: "",
evolutionURL: ""
});
further I make api requests to get information from inside useEffect:
useEffect(() => {
const fetchData = async () => {
await Axios({
method: "GET",
url: urlPokemonAPI
})
.then(result => {
const pokemonResponse = result.data;
/* Pokemon Information */
const img = pokemonResponse.sprites.front_default;
const name = pokemonResponse.name;
const weight = Math.round(pokemonResponse.weight / 10);
const height = pokemonResponse.height / 10;
const types = pokemonResponse.types.map(type => type.type.name);
const abilities = pokemonResponse.abilities.map(
ability => ability.ability.name
);
const moveList = pokemonResponse.moves.map(move => move.move.name);
setPokemon(() => {
return {
img: img,
name: name,
weight: weight,
types: types,
abilities: abilities,
moveList: moveList,
height: height
};
});
})
await Axios({
method: "GET",
url: urlPokemonSpecies
}).then(result => {
let description = "";
result.data.flavor_text_entries.forEach(flavor => {
if (flavor.language.name === "en") {
description = flavor.flavor_text;
}
});
let genus = "";
result.data.genera.forEach(genera => {
if (genera.language.name === "en") {
genus = genera.genus;
}
});
const evolutionURL = result.data.evolution_chain.url;
const eggGroups = result.data.egg_groups.map(
egg_group => egg_group.name
);
const chanceToCatch = Math.round(
(result.data.capture_rate * 100) / 255
);
setPokemon(pokemon => {
return {
...pokemon,
description: description,
genus: genus,
chanceToCatch: chanceToCatch,
evolutionURL: evolutionURL,
eggGroups: eggGroups
};
});
});
};
fetchData();
}, [urlPokemonAPI, urlPokemonSpecies]);
The problem arises specifically with eggGroups (with identical handling of abilities and types there is no such problem). And this is what happens when I want to output data to a page as <div> Egg Group: {pokemon.eggGroups} </div> the data is displayed normally, but as soon as I want to output eggGroups as well as abilities and types separated by commas (join ( ',')) - error: TypeError: pokemon.eggGroups is undefined. I decided to check this matter through the console and stuffed this eggGroups key into the timeout:
At some point, eggGroups becomes undefined ... why, I can’t understand. But if I set the state separately, like const [egg, setEgg] = useState ([]); setEgg (eggGroups); such a problem is not observed. why is this happening? everything was fine with types and abilities. Thank you in advance.
state updater from hooks doesn't merge the state values when updating state, instead it just replaces the old value with new one
Since you use state updater like
setPokemon(() => {
return {
img: img,
name: name,
weight: weight,
types: types,
abilities: abilities,
moveList: moveList,
height: height
};
});
eggGroups property is lost and hence it becomes undefined. You need to update it by spreading the previous state values obtained from callback
setPokemon((prev) => {
return {
...prev
img: img,
name: name,
weight: weight,
types: types,
abilities: abilities,
moveList: moveList,
height: height
};
});
Your code have a problem, this is the proper way to do await with axios,
you need to import axios like this
import axios from 'axios';
the await should be call with a promise, then it return the data from api like this:
const result = await axios.get(urlPokemonAPI);
This is the code snippet with the same logic to your code
useEffect(() => {
const fetchData = async () => {
// import axios from 'axios';
try {
const result = await axios.get(urlPokemonAPI);
const pokemon = result.data;
setPokemon({
img: pokemon.sprites.front_default,
name: pokemon.name,
weight: Math.round(pokemon.weight / 10),
types: pokemon.types.map(i => i.type.name),
abilities: pokemon.abilities.map(i => i.ability.name),
moveList: pokemon.moves.map(i => i.move.name),
height: pokemon.height / 10
});
const result2 = await axios.get(urlPokemonSpecies);
const data = result2.data;
let description = "";
data.flavor_text_entries.forEach(i => {
const lang = i.language.name
if (lang === "en") {
description = i.flavor_text;
}
});
let genus = "";
data.genera.forEach(i => {
const lang = i.language.name;
if (lang === "en") {
genus = i.genus;
}
});
setPokemon(pokemon => {
return {
...pokemon,
description,
genus,
chanceToCatch: Math.round((data.capture_rate * 100) / 255),
evolutionURL,
eggGroups: data.egg_groups.map(g => g.name)
};
});
} catch (e) {
console.log(e);
}
};
fetchData();
}, [urlPokemonAPI, urlPokemonSpecies]);
do you see another problem: you call setPokemon two times, let's rewrite it again:
useEffect(() => {
const fetchData = async () => {
// import axios from 'axios';
try {
const result = await axios.get(urlPokemonAPI);
const data1 = result.data;
const result2 = await axios.get(urlPokemonSpecies);
const data2 = result2.data;
function resolveDescription(data) {
let description = "";
data.flavor_text_entries.forEach(i => {
const lang = i.language.name
if (lang === "en") {
description = i.flavor_text;
}
});
return description;
}
function resolveGenus(data) {
let genus = "";
data.genera.forEach(i => {
const lang = i.language.name;
if (lang === "en") {
genus = i.genus;
}
});
return genus;
}
setPokemon({
img: data1.sprites.front_default,
name: data1.name,
weight: Math.round(data1.weight / 10),
types: data1.types.map(i => i.type.name),
abilities: data1.abilities.map(i => i.ability.name),
moveList: data1.moves.map(i => i.move.name),
height: data1.height / 10,
description: resolveDescription(data2),
genus: resolveGenus(data2),
chanceToCatch: Math.round((data2.capture_rate * 100) / 255),
evolutionURL: data2.evolution_chain.url,
eggGroups: data2.egg_groups.map(g => g.name)
});
} catch (e) {
console.log(e);
}
};
fetchData();
}, [urlPokemonAPI, urlPokemonSpecies]);

Categories

Resources