trying to fill state array with objects - reactjs

I'm using axios in order to fetch some objects, i.e:
zarusd:cur: Object
usdzar:cur: Object
zartry:cur: Object
tryzar:cur: Object
zarsek:cur: Object
sekzar:cur: Object
zarrub:cur: Object
I'm setting my state property to be an array like so:
this.state = {
currecnyData: [],
};
But when I console.log typeof after making the request I get an object. How can I make the state property currecnyData an array hosting each object as an array item so I can use a map method on it?
This is my axios call (without the 'options' parameters):
axios
.request(options)
.then((response) => {
this.setState(
{
currecnyData: [response.data.result],
},
() => {
console.log(typeof this.state.currecnyData);
}
);
})
.catch(function (error) {
console.error(error);
});

this.setState(
{
currecnyData: Object.entries(response.data.result),
}
Object.entries solved my issue! Now I get an array of all the objects.

Object.entries will convert object into an array as you wanted it to be
axios.request(options)
.then((response) => {
this.setState(
{
currecnyData: Object.entries(response.data.result); ,
},
() => {
console.log(typeof this.state.currecnyData);
}
);
})
.catch(function (error) {
console.error(error);
});

Related

How to call a variable inside a then method?

I'm getting client data from the backend and I'am using Axios to call that method.
In then() when I get the response data, I want to make a condition that if its completed, to push it to the new array
export default function Client({selectedClient, setSelectedClient})
console.log(selectedClient) //the value comes
useEffect(() => {
axios
.get('api')
.then((response) => {
const { data } = response; //array of data
console.log(selectedClient) // the value doesn't come
data.forEach(element => {
if (element.CLIENT_ID == selectedClient){
console.log('single element', element)
}
});
})
.catch((error) => console.log("Get Method Error", error.message));
}, []);
So when I put selectedClient inside the then(), it will be empty.
How can I solve this?
You need to have selectedClient as a dependency in useEffect hook. So that hook can updated prop value when component mounts.
export default function Client({selectedClient, setSelectedClient})
console.log(selectedClient) //the value comes
useEffect(() => {
if (selectedClient) {
axios
.get('api')
.then((response) => {
const { data } = response; //array of data
console.log(selectedClient) // the value will come now.
data.forEach(element => {
if (element.CLIENT_ID == selectedClient){
console.log('single element', element)
}
}});
})
.catch((error) => console.log("Get Method Error", error.message));
}, [selectedClient]);
Note - You can remove the added if (selectedClient) { if you wanted to invoke the call even when it's not populated.

How to add 2 new properties to each array item within my object

I am trying to add 2 new properties to each array item within my object before saving it to the state. I need to add Value & Label properties to the Declarations array with the value of the Declarations.countryName. Tried the code below, but not to sure how to achieve this:
public getProfile() {
axios
.post('https://func-portal-dev.azurewebsites.net/api/GetUserProfile',
{
"EmailAddress": "benn.king#erfdfd.co.uk"
})
.then(res => {
console.log('Profile.data:', res.data);
this.setState({profile: res.data.map(p => {
return {
...p,
// New properties I am trying to create
p.Declarations.Value: p.Declarations.countryName,
p.Declarations.Label: p.Declarations.countryName,
}
})
})})
// Error catching
.catch(error => this.setState({ error, isLoading: false }));
}
try this
public getProfile() {
axios
.post('https://func-portal-dev.azurewebsites.net/api/GetUserProfile',
{
"EmailAddress": "benn.king#erfdfd.co.uk"
})
.then(res => {
console.log('Profile.data:', res.data);
let profileData = {...res.data};
profileData.Declarations = res.data.Declarations.map((item)=>{
const newDec = {...item}
newDec.Value = item.countryName;
newDec.Label = item.countryName;
return newDec
})
this.setState(profileData)
})})
// Error catching
.catch(error => this.setState({ error, isLoading: false }));
}

React: Fetched data, but no access to object properties

I successfully fetched data from an API call, in console I see the result, but I can't access object properties or display them.
interface Data {
data: []
isLoading: boolean
}
function About() {
const [ dataUser, setDataUser ] = useState<Data>({data: [], isLoading: false})
useEffect(() => {
setDataUser({data: [], isLoading: true})
fetch('https://jsonplaceholder.typicode.com/users')
.then(response => {
if (!response.ok) {
throw new Error("Failed with HTTP code " + response.status);
}
return response;
})
.then(response => response.json())
.then(data => setDataUser( {data: data, isLoading: false} ))
.catch((err) => {console.log(err)})
}, [])
const user = dataUser.data.map(item => {
console.log(item) //works
console.log(item.id) //doesn't work (error: "Property 'id' does not exist on type 'never'.")
return (<li>{item.name}</li>) //another error ("Objects are not valid as a React child...")
})
return (
<div>
{user}
</div>
)
}
export default About
EDIT
console.log(dataUser.data) ->
I added code for checking if response was ok and everything is fine with that.
console.log(item) ->
Your issue is your interface. I hadn't realized this was a compile-time error, not a run-time error.
interface Data {
data: any[],
isLoading: boolean,
}
The issue is that you're defining Data.data to be an empty array, and the elements of an empty array are of type never. That means that item in your map() callback is of type never, and never has no properties.
You probably want Data.data to be something other than any[] so that item has strongly-typed values, but this should unblock you.

React componentDidMount not setting states before page loads

Working on a MERN application, I have a componentDidMount that uses axios to retrieve from the backend some Ids and retrieve product info(prods) from the ids. However the states in my application are still empty when the page is loaded initially, instead I'll have to make a change to state before the states are set.
I believe it might have something to do with having an array mapping in the componenDidMount, I could change the backend so in node. However i would like to see if anything could be done in the frontend first.
componentDidMount() {
axios
.get("/api/featureds")
.then(response => {
this.setState({
featureIds: response.data
});
response.data.map(({ prodId, _id }) =>
axios
.get("/api/prods/" + prodId)
.then(response => {
if (response.data == null) {
} else {
this.state.featureTempList.push(response.data);
}
})
.catch(error => {
console.log(error);
})
);
this.setState({
featureProds: this.state.featureTempList
});
})
.catch(error => {
console.log(error);
});
}
Why are you trying to set state like this?
this.state.featureTempList.push(response.data)
State should be set by this.setState().
So you can try doing this:
this.setState((oldState) => ({
featureTempList: oldState.featureTempList.push(response.data)
});
Just remember to set featureTempList to state when you initialize:
state = {
featureTempList: []
}

ReactJS setState when all nested Axios calls are finished

I have a problem with updating my state from nested axios call inside forEach loop:
constructor(props) {
super(props);
this.state = {
isLoaded: false,
items: []
};
//Binding fetch function to component's this
this.fetchFiles = this.fetchFiles.bind(this);
}
componentDidMount() {
this.fetchFiles();
}
fetchFiles() {
axios.get('/list')
.then((response) => {
var items = response.data.entries;
items.forEach((item, index) => {
axios.get('/download'+ item.path_lower)
.then((response) => {
item.link = response.data;
})
.catch(error => {
console.log(error);
})
});
this.setState(prevState => ({
isLoaded: true,
items: items
}));
console.log(this.state.items);
})
.catch((error) => {
console.log(error);
})
}
The idea is to get all items from Dropbox using it's API (JavaScript SDK)
and then for each item I also need to call different API endpoint to get a temporary download link and assign it as a new property. Only after all items will get their links attached I want to setState and render the component. Could somebody please help with this, I spend already multiple hours fighting with promises :S
You could use Promise.all to wait for multiple promises. Also keep in mind that setState is async and you wont see immediate changes. You need to pass a callback.
fetchFiles() {
axios.get('/list')
.then((response) => {
var items = response.data.entries;
// wait for all nested calls to finish
return Promise.all(items.map((item, index) => {
return axios.get('/download'+ item.path_lower)
.then((response) => {
item.link = response.data;
return item
});
}));
})
.then(items => this.setState(prevState => ({
isLoaded: true,
items: items
}), () => console.log(this.state.items)))
.catch((error) => {
console.log(error);
})
}
Try making the fetchfiles() function as an asynchronous method by adding the async keyword.Now, we have to wait till the items to get their download link, so add a await keyword before that line which makes the code to wait till the axios call gets completed.
async function fetchFiles() {
axios.get('/list')
.then(async function(response){
var items = response.data.entries;
await items.forEach((item, index) => {
axios.get('/download'+ item.path_lower)
.then((response) => {
item.link = response.data;
})
.catch(error => {
console.log(error);
})
});
this.setState(prevState => ({
isLoaded: true,
items: items
}));
console.log(this.state.items);
})
.catch((error) => {
console.log(error);
})
}
I haven't tested the code, but it should probably work.

Resources