How to update an object that is within an array - javascript

How can I put data into object values in an array in javaScript? I am taking data from the backend using axios and useEffect hook! taking data I need to push that data into an object which is inside of the array! code I wrote doesn't work and ignorant! there is a JS question!
const Articles = () => {
const [articleData, setArticleData] = useState([]);
useEffect(() => {
const fetchBlogs = async () => {
try {
const res = await axios.get(
`${process.env.REACT_APP_API_URL}/article/list/all`
);
setArticleData(res.data);
} catch (err) {}
};
fetchBlogs();
}, []);
for (let article in articleData) {
data: [
{
key: article._id,
title: article.title,
author_username: article.author_username,
category: article.category_name,
subcategory: article.subCategory_name,
publication_date: article.publication,
},
],
}
return (
<div className='articles'>
<Table
columns={columns}
dataSource={data}
size='large'
/>
</div>
)
};

You can use map to get a new array, then save it to the state and use the state variable in JSX. Something like this should work for you
const Articles = () => {
const [articleData, setArticleData] = useState([]);
useEffect(() => {
const fetchBlogs = async () => {
try {
const res = await axios.get(
`${process.env.REACT_APP_API_URL}/article/list/all`
);
setArticleData(res.data.map(article => ({
key: article._id,
title: article.title,
author_username: article.author_username,
category: article.category_name,
subcategory: article.subCategory_name,
publication_date: article.publication,
})));
} catch (err) {}
};
fetchBlogs();
}, []);
return (
<div className='articles'>
<Table
columns={columns}
dataSource={articleData}
size='large'
/>
</div>
)
};

Related

How to pass data from an axios API inside a state using React?

I have an api (an arr of objects) which I need to pass into a state, so that I can then pass that data inside a component to show it on the website.
1st approach:
// pulls the api data
const newData = axios.get(url).then((resp) => {
const apiData = resp.data;
apiData.map((video) => {
return video;
});
});
// sets the state for the video
const [selectedVideo, setSelectedVideo] = useState(newData[0]);
const [videos] = useState(videoDetailsData);
...
return (
<>
<FeaturedVideoDescription selectedVideo={selectedVideo} />
</>
)
2nd approach:
const useAxiosUrl = () => {
const [selectedVideo, setSelectedVideo] = useState(null);
useEffect(() => {
axios
.get(url)
.then((resp) => setSelectedVideo(resp.data))
});
return selectedVideo;
}
...
return (
<>
<FeaturedVideoDescription selectedVideo={selectedVideo} />
</>
)
both of these approaches don't seem to work. What am I missing here?
The correct way is to call your axios method inside the useEffect function.
const fetchData = axios.get(url).then((resp) => setSelectedVideo(resp.data)));
useEffect(() => {
fetchData();
}, [])
or if you need async/await
useEffect(() => {
const fetchData = async () => {
const response = await axios.get(url);
setSelectedVideo(resp.data);
}
fetchData();
}, [])

Proper way to fetch from another component - ReactJS

I have a component that fetches the data properly but I want to encapsulate it in a helper. I've tried many things but I'm stuck.
This is the component that works:
export const Carousel = () => {
const [ lotteries, setLotteries ] = useState({});
const [ isLoading, setisLoading ] = useState(true);
useEffect(() => {
async function fetchAPI() {
const url = 'https://protected-sea-30988.herokuapp.com/https://www.lottoland.com/api/drawings;'
let response = await fetch(url)
response = await response.json()
setLotteries(response)
setisLoading(false)
}
fetchAPI()
}, [])
return (
<>
{
isLoading ? (
<span>loading</span>
) : (
<Slider >
{
Object.keys(lotteries).map((lottery, idx) => {
return (
<Slide
key={ idx }
title={ lottery }
prize={ lotteries[lottery].next.jackpot }
day={ lotteries[lottery].next.date.day }
/>
)
})
}
</Slider>
)}
</>
);}
And this is the last thing I've tried so far. This is the component without the fetch
export const Carousel = () => {
const [ lotteries, setLotteries ] = useState({});
const [ isLoading, setIsLoading ] = useState(true);
useEffect(() => {
getLotteries()
setLotteries(response)
setIsLoading(false)
}, [])
And this is where I tried to encapsulate the fetching.
export const getLotteries = async() => {
const url = 'https://protected-sea-30988.herokuapp.com/https://www.lottoland.com/api/drawings;'
let response = await fetch(url)
response = await response.json()
return response;
}
I'm a bit new to React, so any help would be much appreciated. Many thanks.
To get the fetched data from getLotteries helper you have to return a promise
export const getLotteries = async() => {
const url = 'https://protected-sea-
30988.herokuapp.com/https://www.lottoland.com/api/drawings;'
let response = await fetch(url)
return response.json()
}
and call it as async/await
useEffect(async() => {
let response= await getLotteries()
setLotteries(response)
setIsLoading(false)
}, [])
If you want to separate the logic for requesting a URL into another helper function, you can create a custom hook.
// customHook.js
import { useEffect, useState } from 'react';
export function useLotteries() {
const [lotteries, setLotteries] = useState(null);
useEffect(() => {
fetch('https://protected-sea-30988.herokuapp.com/https://www.lottoland.com/api/drawings;')
.then(response => response.json())
.then(json => setLotteries(json));
}, []);
return lotteries;
}
// Carousel.js
import { useLotteries } from "./customHook.js";
export const Carousel = () => {
const lotteries = useLotteries();
if (lotteries) {
return; /* Your JSX here! (`lotteries` is now contains all the request responses) */
} else {
return <Loader />; // Or just null if you don't want to show a loading indicator when your data hasn't been received yet.
}
};

Using async function, await and resolve in React component

I have a component with the following structure:
const _dbCall = () => {
const fooDb = SQLite.openDatabase(db);
return new Promise(resolve => {
fooDb.transaction(tx => {
tx.executeSql(`SOME SQL`, [], (tx, results) => {
resolve(results.rows._array);
}, null);
});
})
}
async function _renderSomething() {
const results = await _dbCall();
return <FlatList
data={results}
renderItem={_renderFunc}
keyExtractor={item => item} />
}
I use _renderSomething() in the render() function of the Component.
However, this gives me:
Error: Objects are not valid as a React child (found: object with keys {_U, _V, _W, _X}). If you meant to render a collection of children, use an array instead.
This {_U, _V, _W, _X} looks like an unresolved promise to me.
When I remove the async keyword from renderSomething(), comment the const results = ... and pass some dummy data to <FlatList ..., it renders without a problem.
Why does renderSomething() not return the <FlatList ... but an unresolved promise?
As #Yousaf pointed out:
const [resultsFromDb, setResultsFromDb] = useState([]);
const _dbCall = () => {
const foo = [];
const fooDb = SQLite.openDatabase(db);
fooDb.transaction(tx => {
tx.executeSql(`SOME SQL`, [], (tx, results) => {
// do something the results
for (let i = 0; i < results.rows.length; i++) {
foo.push(results.rows.item(i));
}
setResultsFromDb(foo)
}, null);
});
}
const _renderSomething = () => {
const results = _dbCall();
return <FlatList
data={resultsFromDb}
renderItem={_renderFunc}
keyExtractor={item => item} />
}
You can use in useEffect hook.
function _renderSomething() {
const [data,setData] = React.useState([])
React.useEffect(()=>{
(async () => {
const results = await _dbCall();
setData(results);
})()
}, []);
return <FlatList
data={data}
renderItem={_renderFunc}
keyExtractor={item => item} />
}

Displaying Nested JSON in React/JSX

I have some JSON that is formatted like this:
{
card_id: "afe1500653ec682b3ce7e0b9f39bed89",
name: "A.J. Burnett",
playerattribute: {
team: "Marlins",
rarity: "Diamond",
}
}
I'm attempting to display the name and the team in a component. Here is what I have.
const PlayerProfile = ({ match, location }) => {
const { params: { cardId } } = match;
const [player, setPlayer] = useState(0);
useEffect(() => {
const fetchData = async () => {
const result = await axios(
`http://127.0.0.1:8000/api/player-profiles/${cardId}/?format=json`,
).then((result) => {
setPlayer(result.data);
});
};
fetchData();
}, []);
return (
<Container component="main">
Name: {player.name}
Team: {player.playerattribute.team}
</Container>
)
}
export default PlayerProfile;
However, I get this error: TypeError: Cannot read property 'team' of undefined
The name works fine. So I'm assuming it's an issue with the nested JSON.
You probably shouldn't instanciate your player state with 0 if the projected value is an object.
The error comes up because you try to access a property of an object property that doesn't exist at creation.
Basically, your code tries to do this: {0.playerattribute.team}
0.playerattribute => undefined
Workaround would be a conditionnal render or a default initial value of your state that matches the JSX needs.
const PlayerProfile = ({ match, location }) => {
const { params: { cardId } } = match;
const [player, setPlayer] = useState({
name: "",
playerattribute: {
team: ""
}
});
useEffect(() => {
const fetchData = async () => {
const result = await axios(
`http://127.0.0.1:8000/api/player-profiles/${cardId}/?format=json`,
).then((result) => {
setPlayer(result.data);
});
};
fetchData();
}, []);
return (
<Container component="main">
Name: {player.name}
Team: {player.playerattribute.team}
</Container>
)
}
export default PlayerProfile;
or
const PlayerProfile = ({ match, location }) => {
const { params: { cardId } } = match;
const [player, setPlayer] = useState(null);
useEffect(() => {
const fetchData = async () => {
const result = await axios(
`http://127.0.0.1:8000/api/player-profiles/${cardId}/?format=json`,
).then((result) => {
setPlayer(result.data);
});
};
fetchData();
}, []);
return (
<Container component="main">
Name: {player?.name}
Team: {player?.playerattribute?.team}
</Container>
)
}
export default PlayerProfile;
Set useState const [player, setPlayer] = useState("");
const [player, setPlayer] = useState({
Name: '',
Team: ''
}}
//on your setPlayer you may
const playerData = result.data;
setPlayer({
Name: playerData.name
Team: playerData.playerattribute.team})
if you still getting same error, please provide screenshot of console.log(result)

React map function does not execute when the component is rendered

As you can see below in the dev tools screen shot, the child element does have props. My issue is I cannot get them to appear in the DOM when the component is first rendered. I have to click on the Link element again to re-render the component and only then does the map function work correctly (second screen shot). Another thing is I am using the same code in another component and it works fine. Help!
import React, { useState, useEffect } from 'react'
import firebase from 'firebase';
import NewsLetterListChildComponent from './children/NewsLetterListChildComponent';
import LoadingComponent from '../Loading/LoadingComponent';
function PublicNewsLetterListComponent({ user }) {
const [ newsLetters, setNewsLetters ] = useState([]);
const [ loading, setLoading ] = useState(false);
const [ errors, setErrors ] = useState(false);
useEffect(() => {
let requestCancelled = false;
const getNewsLetters = () => {
setLoading(true);
let newsLetterArray = [];
firebase
.firestore()
.collection('newsLetters')
.get()
.then((querySnapshot) => {
querySnapshot.forEach((doc) => {
const listRef = firebase.storage().ref().child('newsLetterImagesRef/' + doc.id);
listRef
.getDownloadURL()
.then(url => {
newsLetterArray.push({ id: doc.id, data: doc.data(), image: url });
})
.catch(error => console.log(error))
});
});
setNewsLetters(newsLetterArray);
setLoading(false);
};
getNewsLetters();
return () => {
requestCancelled = true;
};
}, []);
const renderContent = () => {
if(loading) {
return <LoadingComponent />
} else {
return <NewsLetterListChildComponent newsLetters={newsLetters} />
}
}
return renderContent();
}
export default PublicNewsLetterListComponent
import React from 'react';
import { ListGroup, ListGroupItem, Row, Col } from 'reactstrap';
function NewsLetterListChildComponent({ newsLetters }) {
return (
<div>
<Row>
<Col md={{size: 6, offset: 3}}>
<ListGroup>
{newsLetters.map((item, index) => {
return (
<ListGroupItem key={index} className="m-1" ><h1>{item.data.title} </h1><img src={item.image} alt={item.data.title} className="thumb-size img-thumbnail float-right" /></ListGroupItem>
);
})}
</ListGroup>
</Col>
</Row>
</div>
)
}
export default NewsLetterListChildComponent;
Initial render and the list group is empty
after the re-render and now the list group is populated
You need to call setNewsLetters when the data is resolved:
const getNewsLetters = async () => {
setLoading(true);
try {
const newsLetters = await firebase
.firestore()
.collection("newsLetters")
.get();
const data = await Promise.all(
newsLetters.docs.map(async (doc) => {
const url = await firebase
.storage()
.ref()
.child("newsLetterImagesRef/" + doc.id)
.getDownloadURL();
return {
id: doc.id,
data: doc.data(),
image: url,
};
})
);
setNewsLetters(data);
} catch (error) {
console.log(error);
} finally {
setLoading(false);
}
};
The useEffect code contains an async request and you are trying to update an array of newsLetters in state even before it will be fetched. Make use of Promise.all and update the data when it is available
useEffect(() => {
let requestCancelled = false;
const getNewsLetters = () => {
setLoading(true);
firebase
.firestore()
.collection('newsLetters')
.get()
.then((querySnapshot) => {
const promises = querySnapshot.map((doc) => {
const listRef = firebase.storage().ref().child('newsLetterImagesRef/' + doc.id);
return listRef
.getDownloadURL()
.then(url => {
return { id: doc.id, data: doc.data(), image: url };
})
.catch(error => console.log(error))
Promise.all(promises).then(newsLetterArray => { setNewsLetters(newsLetterArray);})
});
});
setLoading(false);
};
getNewsLetters();
return () => {
requestCancelled = true;
};
}, []);
If you check newletters with if, your problem will most likely be resolved.
review for detail : https://www.debuggr.io/react-map-of-undefined/
if (newLetters){
newLetters.map(item=> ...)
}

Categories