React Rest API issue - javascript

I´m new to REST API and on the current project where I can create gallery categories and images inside the gallery I bumped into a problem.
I have multiple objects within the parent array as seen below. Some of them containing image.
[]
0:
0: {path: "test", name: "test"}
1: {path: "puli", image: {…}, name: "puli"}
2: {path: "animalsg", name: "animalsg"}
3: {path: "animals", image: {…}, name: "animals"}
4: {path: "Animals", image: {…}, name: "Animals"}
5: {path: "sdfsf", name: "sdfsf"}
6: {path: "viki", name: "viki"}
7: {path: "pul", image: {…}, name: "pul"}
8: {path: "testik", name: "testik"}
__proto__: Object
length: 1
__proto__: Array(0)
Is there a way to fetch all the name values from each object and also assign it an id?
Can you please help me modify this useEffect for this purpose?
useEffect(() => {
const tempAlbum = [];
fetch('http://someapi.xy/gallery')
.then(response => response.json())
.then(data => tempAlbum.push('???'));
}, [])

If I understood right, you would want to do something like this
useEffect(() => {
const tempAlbum = [];
fetch('http://someapi.xy/gallery')
.then(response => response.json())
.then(data => { data[0].forEach(
(item,i) => {
tempAlbum.push({name: item.name, id: i})
})
});
}, [])
About the id, this approach is using the same array index as id, that could work for you unless you need this id to render this array on your React application, in which case using the index is not recommended, so you could use a library like uuid to generate an id on the fly, it's very simple to use and does not require configuration.

If what you are trying to do is simply get an tempAlbum to have an array of like [{ name: 'rockers', id: '1234'}, ...] then you can do:
data.flat().forEach((x, idx) => tempAlbum.push({ name: x.name, id: idx }));
That should work for you.

Related

Array being filled in inverse in React

I am trying to fill an array with several array of objects, but on first render, the values are being filled in inverse inside the array and after refreshing they go back to how they should be.
const getProducts = async (data) => {
await productServices
.getProductsByTakeoffWizardStep(data)
.then((response) => {
setRows((rows) => [...rows, response.data]);
})
.catch((error) => {
console.log(error.response);
});
};
const getTakeoffIDs = () => {
var i = 1;
takeoffServices
.getTakeoffSteps(5)
.then((response) => {
response.data.forEach((element) => {
setSteps((steps) => [...steps, element.description]);
setStepsID((stepsID) => [...stepsID, element.stepID]);
var data = { StepID: element.stepID, TakeoffID: 4 };
getProducts(data);
setStepSequence((stepSequence) => [
...stepSequence,
"Step " + i + "",
]);
i = i + 1;
});
})
.catch((error) => {
console.log(error.response);
});
};
useEffect(() => {
setSteps([]);
setStepsID([]);
setRows([]);
getTakeoffIDs();
}, []);
So on first render the array looks like this
(2) [Array(1), Array(2)]
0: Array(1)
0: {product: {…}, quantity: null}
length: 1
[[Prototype]]: Array(0)
1: Array(2)
0: {product: {…}, quantity: null}
1: {product: {…}, quantity: null}
length: 2
[[Prototype]]: Array(0)
length: 2
[[Prototype]]: Array(0)
and after refreshing the page it looks like this
(2) [Array(2), Array(1)]
0: Array(2)
0: {product: {…}, quantity: null}
1: {product: {…}, quantity: null}
length: 2
[[Prototype]]: Array(0)
1: Array(1)
0: {product: {…}, quantity: null}
length: 1
[[Prototype]]: Array(0)
length: 2
[[Prototype]]: Array(0)
What could be causing this and what can I do to fix it?
I am accessing the page using history.push() from another page but none of the states I am passing affects the fetching process, only the display of some paragraphs not related to the data I am fetching.
This is how I would write this:
const getProduct = async (data) => {
try {
const response = await productServices.getProductsByTakeoffWizardStep(data);
return response.data;
} catch (error) {
console.log(error.response);
}
}
const getTakeoffIDs = () => {
takeoffServices
.getTakeoffSteps(5)
.then(async (response) => {
// try moving setSteps(), setStepsID() and setStepSequence() up here, so they don't wait for the products.
const products = await Promise.all(
response.data.map(element => getProduct({
StepID: element.stepID,
TakeoffID: 4
}))
);
setRows((rows) => [
...rows,
...products
]);
setSteps((steps) => [
...steps,
...response.data.map(element => element.description)
]);
setStepsID((stepsID) => [
...stepsID,
...response.data.map(element => element.stepID)
]);
setStepSequence((stepSequence) => [
...stepSequence,
...response.data((_, i) => `Step ${i + 1}`)
]);
})
.catch((error) => {
console.log(error.response);
});
};
useEffect(() => {
setSteps([]);
setStepsID([]);
setRows([]);
getTakeoffIDs();
}, []);
Instead of calling all these setState()s multiple times I'd Array.map() the data and add it all at once.
await for all the getProduct() calls to finish and also push them at once; in order.
The one thing I'm not sure about is if you want the setRows() to be called together with the other setter, or if the other ones should go first (because the data is available) and setRows() should be called later, as soon as the data is available.

Alternative for ForEach loop in Javascript?

I'm working with array where it contains array of array object and I tried with ForEach loop now its working fine but I want to know any way to improvise the performance of my array and combined into key value pair as my final result.
0:
Project: {Division__c: "Mechanical", Owner: {…}, Id: "009921",OwnerId: "005C00000049TRKIA2", …}
TaskList: Array(1)
0:
Case: {Owner: {…},Priority: "Normal", Id: "00118627"}
and my code is
Project.forEach(wrappedProject => {
result.push({'label':Project.TaskList.Owner.Name,'value':wrappedProject.TaskList.Owner.Name})
Project.TaskList.forEach(Task =>{
Task.Case.forEach(task => {
console.log('task',task)
ownerResult.push({'label':task.Owner.Name,'value':task.Owner.Name})
});
})
});

Array prop returns Observer so can't access at [0]

I passed Array but got Observer here's my code:
In Component1
data() {
return {
myWords: [],
}
}
//...
await axios.post(this.serverUrl + router, {
voca: text,
category: this.buttonGroup.category.text
})
.then(res => {
this.myWords.push({
voca: this.voca,
vocaHeader: this.vocaHeader,
category: res.data.savedVoca.category,
date: res.data.savedVoca.date,
id: res.data.savedVoca._id
})
this.myWords.push({voca:"test"})
})
.catch(err => {
console.log(err)
})
In Component2
props: {
myWordsProp: {
type: Array,
default: () => ([])
},
},
mounted() {
console.log(this.myWordsProp)
console.log(this.myWordsProp[0]) //returns undefined
},
And I expected an Array but I get Observer so I can't get values from this.myWordsProp[0] why?
//this.myWordsProp
[__ob__: Observer]
0: {
category: "ETC"
date: "2018-11-21T15:31:28.648Z"
id: "5bf57a503edf4e0016800cde"
voca: Array(1)
vocaHeader: Array(1)
...
}
1: {__ob__: Observer}
length: 2
__ob__: Observer {value: Array(2), dep: Dep, vmCount: 0}
__proto__: Array
//this.myWordsProp[0]
undefined
I found a clue that when I test it outside of axios it worked as I expected.
Vue wraps data and props into reactive objects. Use vue-devtools plugin in your browser as an alternative to viewing the ugly observer in the console.
In your code, the object behaves correctly. It’s only in the console that it ‘looks’ different.
Anyway, you can also click on the ... to expand the node and get the value from the console.
https://github.com/vuejs/vue-devtools
I found a solution It's because of sending props before get data from server.
This is my whole of postVocas function It returns promise
postVocas: function (voca) {
if (!voca || voca.length < 1) return
let router = "/api/voca"
let text = ""
text += `${this.vocaHeader[0].english}, ${this.vocaHeader[0].korean}\n`
voca.forEach((x, index) => {
text += `${voca[index].english}, ${voca[index].korean}\n`
})
return axios.post(this.serverUrl + router, {
voca: text,
category: this.buttonGroup.category.text
}).then(res => {
this.myWords.push({
voca: this.voca,
vocaHeader: this.vocaHeader,
category: res.data.savedVoca.category,
date: res.data.savedVoca.date,
id: res.data.savedVoca._id
})
}).catch(err => {
console.log(err)
})
},
And await till get data from server.
This one is function where execute My postVocas function.
sendVocaToTable: async function () {
let reformedText = this.reformText(this.text)
this.voca = this.formatTextToVoca(reformedText)
await this.postVocas(this.voca)
this.$router.push({
name: 'Table',
params: {
vocaProp: this.voca,
tableHeaderProp: this.vocaHeader
}
})
},

.map is not a function - react

I'm trying to map over an API response but it gives me "TypeError: response.map is not a function".
I think it might be due to the map method getting a string instead of an array. but when I console.log it gives me an array so I can't really see where the error comes from.
Or maybe I'm accessing the API response array in a wrong way.
I've read tons of documentation and threads but still can't get what am I doing wrong.
Thanks in advance
{status: {…}, outputs: Array(1), rawData: {…}}
outputs: Array(1)
0:
created_at:"2018-08-24T19:58:44.351091715Z"
data:
concepts:Array(20)
0:{id: "ai_69gDDQgl", name: "hamburger", value: 0.9955255, app_id: "main"}
1:{id: "ai_QLn2rxmZ", name: "lettuce", value: 0.9920815, app_id: "main"}
const IngredientsList = ({ response }) => {
const items = response.map((item) =>
<ul>{item}</ul>)
return (
<div>
<p>{items}</p>
</div>
)
}
This would render the concepts array with name and value in a list?
const IngredientsList = ({ response }) => {
if (!response || !response.outputs) {
return null;
}
const items = response.outputs[0].data.concepts.map((item) => <li>name: {item.name}, value: {item.value}</li>);
return (
<div>
<ul>{items}</ul>
</div>
)
}

spread operator (...) is creating extra fields in array in es6

I wanted to embed a new key/value pair in the respective indexed array of objects based on an onChange event.
However, it is done correctly but adding extra elements in the array.
Original array of objects:
0:{data: {…}}
1:{data: {…}}
2:{data: {…}}
3:{data: {…}}
4:{data: {…}}
Achieved result:
0:{data: {…}}
1:{data: {…}}
2:{data: {…}, origin: "UK"}
3:{data: {…}, origin: "UK"}
4:{data: {…}}
5:"UK"
6:"UK"
Intended result:
0:{data: {…}}
1:{data: {…}}
2:{data: {…}, origin: "UK"}
3:{data: {…}, origin: "UK"}
4:{data: {…}}
Below is my code doing it in a loop:
render: (rowData, indexes) => {
return (
<SelectField
id={`origin-${indexes.rowIndex}`}
defaultValue="US"
style={{ position: 'absolute' }}
onChange={text => {
this.setState(
{
generalPermitSelectedVehicles: [
...generalPermitSelectedVehicles,
(generalPermitSelectedVehicles[
indexes.rowIndex
].origin = text),
],
},
() => {
console.log({
generalPermitSelectedVehicles: this.state
.generalPermitSelectedVehicles,
});
},
);
}}
menuItems={[
{
label: 'America',
value: 'US',
},
{
label: 'United Kingdom',
value: 'UK',
},
{
label: 'Oman',
value: 'Oman',
},
]}
/>
);
},
Write it like this:
this.setState(prevState => {
let data = [...prevState.generalPermitSelectedVehicles];
data[indexes.rowIndex].origin = text;
return {generalPermitSelectedVehicles: data};
})
Why its failing in your case?
Because when you do:
[...arr, (arr[index].origin=10)]
It will do two things, first it will update the value of origin at that index, second it will add 10 (returned 10 from ()) at the end of array also.
Check this snippet:
let arr = [{a:1}, {a:2}, {a:3}];
arr = [...arr, (arr[1].a=500)]; //500 will get added in the last
console.log('new value', arr);
Suggestion: Use updater function (prevState) because next state (value) of generalPermitSelectedVehicles is dependent on previous value.
Check the DOC for more details about setState updater function.
You need to update the original state and not append it. You are not using spread operator correctly. Also make use of functional setState when you want to update state based on prevState. You would need to do
this.setState(
prevState => ({
generalPermitSelectedVehicles: [
...prevState.generalPermitSelectedVehicles.slice(0, index.rowIndex),
{...prevState.generalPermitSelectedVehicles[
indexes.rowIndex
], origin: text},
...prevState.generalPermitSelectedVehicles.slice(index.rowIndex + 1)
],
},
() => {
console.log({
generalPermitSelectedVehicles: this.state
.generalPermitSelectedVehicles,
});
},
);
The error in your approach is that you are appending the updated state after spreading the original state, you need to update the existing instead.
Also check this answer on how to update nested state

Categories