What is the best way of calculating the total amount (quantity*price) from the array of objects (State) in react? - reactjs

I have an array of objects as my initial state like
const [product,setProduct]=useState([
{
id:1,
product_title:"Item 1",
quantity:2,
price:100.00
},
{
id:2,
product_title:"Item 2",
quantity:3,
price:300.00
},
])
Here I am also adding more items and at the same time, I Want to calculate the total amount based on quantity*price of each item from the objects. Right now I am proceeding with map() function like this code below and I am getting the exact result
const countTotal=(items)=>
{
var total=0;
product.map(item=>total+=item.quantity*item.price)
setTotal(total)
}
Now My question is if it is a good process or there is an alternative way that is better and standard than this process.

As a general rule, if you have array and want to single value based on all values, you need Array.proptotype.reduce()
const products = [
{
id:1,
product_title:"Item 1",
quantity:2,
price:100.00
},
{
id:2,
product_title:"Item 2",
quantity:3,
price:300.00
},
];
const countTotal = (items) => items.reduce((acc, curr) => acc + curr.quantity * curr.price, 0);
console.log(countTotal(products))

You are using .map method incorrectly, you should use reduce method instead, like this
const total = product.reduce((prev, cur) => {
return prev + cur.quantity * cur.price;
}, 0);

Related

React filter object and change value within child object

I am trying to use filter to make my life easier.
My goal: Change the closeTime.hours of filter openDay(TUESDAY)
I have an array of objects that looks like:
buildHours = [
{
"openDay": "MONDAY",
"openTime": {},
"closeDay": "MONDAY",
"closeTime": {
"hours": 24
}
},
{
"openDay": "TUESDAY",
"openTime": {
"hours": 9
},
"closeDay": "TUESDAY",
"closeTime": {
"hours": 17
}
},
]
How I am doing this right now is removing the "Tuesday" Object using
const tempObject = buildHours.filter(i => i.openDay !== "TUESDAY"); // Destroy Tues
const tempHours = buildHours.filter(i => i.openDay === "TUESDAY")[0]; // Save Tues Obj
tempHours.openTime.hours = e.value; // Change Hour
tempObject.push(tempHours); // Recombine
console.log(tempObject);
Then "rebuilding" the "TUESDAY" object and adding it back to the main object. Although it works .. It seems a little convoluted. Isn't there a way I can use a combination of filter() and set closeTime.hours = 17? I have tried 6 ways to Sunday and nothing seems to work.
Is the way I am doing it right now the preferred method? Remove the object, rebuild and combine?
Or is there a more elegant way to change the hours for Tuesday without destroying the object and rebuilding it in the process?
Without knowing the rest of the context, it's hard to say what the "best" way to do this would be... but, generally, I'd use map instead of filter; something like:
const buildHours = [ /* ... */ ]; // no change to this
const handleHourChange = (e) => {
return buildHours.map(o => {
if (o.openDay !== 'TUESDAY') return o;
return {
...o,
openTime: {
...o.openTime,
hours: e.value,
},
};
};
});
Also - one minor point on your code - instead of using filter to find the Tuesday object, you can use find -
const tempHours = buildHours.find(i => i.openDay === "TUESDAY");
And even if you did want to use filter and just get the first one, you can use array destructuring:
const [tempHours] = buildHours.filter(i => i.openDay === "TUESDAY");

How to return objects that have matching value when comparing to a separate array

In my state I have an object called foodLog which holds all entries a user enters with one of the keys being foodSelectedKey and I'm trying to return all entries that have a matching value from that key with a different array called foodFilter.
However, this doesn't work and errors out saying foodLog.filter() isn't a function - I've looked this up and it's because it's an Object (I think). Any help would be greatly appreciated!
state = {
// log food is for the logged entries
foodLog: {},
// used for when filtering food entries
foodFilter: [],
};
findMatches = () => {
let foodLog = this.state.foodLog;
let foodFilter = this.state.foodFilter;
let matched = foodLog.filter((item) => {
return foodLog.foodsSelectedKey.map((food) => {
return foodFilter.includes(food);
});
});
};
I guess the reason behind the error Is not a function is that the object can not be looped. By that it means you can not iterate an object with differend variables inside, if it has no index to be iterated like an array. The same goes for map(), find() and similar functions which MUST be run with arrays - not objects.
As far as I understand you have an object named foodLog which has an array named foodsSelectedKey. We need to find intersected elements out of foodFilter with the array. This is what I came up with:
state = {
// log food is for the logged entries
foodLog: {
foodsSelectedKey: [
{ id: 1, name: "chicken" },
{ id: 2, name: "mashroom" }
]
},
// used for when filtering food entries
foodFilter: [
{ id: 1, name: "chicken" },
{ id: 2, name: "orange" }
]
};
findMatches = () => {
let foodLog = this.state.foodLog;
let foodFilter = this.state.foodFilter;
let matched = foodLog.foodsSelectedKey.filter((key) =>
{
for (let i=0; i<foodFilter.length;i++){
if(foodFilter[i].name===key.name)
return true
}
return false;
}
);
return matched;
};
The Output is filtered array, in this case, of one element only:
[{
id: 1
name: "chicken"
}]
In order to check the output - run console.log(findMatches()). Here is the CodeSandbox of the solution. (check console at right bottom)

Insert list data over the iteration(map)

Here I am trying to modify my data over the iteration and send some result to API call.
The API Call receives a request with a structured data format which is
{ list: [{ id: "1", name: "Hello" }, ... ] }
Somehow I managed to call the API with single data ( const params in my current code, it only accepts single data).
But now it has to be done with multiple data something like this:
{ list: [{ id: "1", name: "Hello" }, { id: "22", name: "Ed" }, { id: "36", name: "Jason" } ... ] }
Here is my current code
const [table, setTalbe] = useState(..); // assume, we have some table data here
const processNow = () => {
let id = 0;
let name = '';
// if table length is greater than 1, we go for the loop.
if (table.length >= 1) {
table.map(data => {
id = data.userId;
name = data.userName;
});
//insert table data to params, here I want to add whole table data into "list"
//the final result of this list should be something like this
//ex ) list: [{ id: '123', name: 'Josh' }, { id: '125', name: 'Sue' }, { id: '2222', name: 'Paker' } ...],
// but how??
const params: any = {
list: [
{
id: id,
name: name
},
],
};
//send PUT reqeust with params
axios
.put(
'/api/v1/tosent',
params,
)
.then(res => {
console.log('The response', res);
})
.catch(err => {
console.log('The error: ', err);
});
}
};
but I'm stuck with it, please help me to finish this code to work properly.
need your kind advice.
Array.prototype.map returns a new array with the function you pass applied to every element. You should study the MDN documentation on map to understand its use.
Your current code does nothing with the map return value:
table.map(data => {
id = data.userId;
name = data.userName;
});
You probably assumed .map would mutate the data, as in change it in place. Instead, the whole operation returns a new array.
It looks like you want to do:
const list = table.map(data => {
return {
id: data.userId,
name: data.userName
}
});
This is applying a function to every element in the array that will map each element to a new object, matching your question, with an id and name key. Then it looks like you want to pass the returned value of map (which we named list above) to your call:
const params: any = {
list: list
};

How to remove the right element from array react?

I want to remove an element from my array when click on a specific row.
When I click on an element it does nothing or the last row gets deleted.
I tried to remove the element like this:
ondeleterow(e: any) {
const array = [...this.state.fields.columns]; // make a separate copy of the array
const index = array.indexOf(e.target.id);
if (index !== -1) {
array.splice(index, 1);
this.setState({ fields: { columns: array }});
}
}
My array/json object looks like this:
[ {index: 0, name: "person 1", age: 12},
{index: 1, name: "person 2", age: 19},
{index: 2, name: "person 3", age: 34},
]
My result should be when I click on a row with ID=1 the row with index: 1 gets deleted from my state array.
I can't give them an Id because when I submit the json structure then does not get accepted.
I feel like your Array.splice might be causing the issue here (because even though you created a new array, the objects in the array are still passed by reference).
I would recommend a completely different method of doing this operation which I've found to be far cleaner and robust.
First you have to add a unique id field to each row. (this is good practice in react anyway, instead of using index for keys).
ondeleterow(id: string) {
return (e: any) => {
const array = this.state.fields.column.filter(item => item.id != id)
this.setState({ fields: { columns: array }});
}
}
and when you're mapping over your rows, you can simply add the function to the onClick like this
<Row key={item.id} onClick={ondeleterow(item.id)} />
Never use splice in react especially with state. They directly mutate the data. Use non mutating operations like slice.
Your code should as follows
ondeleterow(e: any) {
const array = [...this.state.fields.columns]; // make a separate copy of the array
const index = array.indexOf(e.target.id);
if (index !== -1) {
array.splice(index, 1);
this.setState({ fields: {
columns: [ ...array.slice(0, index), ...array.slice(index + 1, array.length) ]
}});
}
}
You can use Array.filter. This will allow you to create a new array with only the items you want based on a certain criteria. In this case, you want an array with items that have a different ID that the one you want to remove. So it will look like this
// Actual processing
const filterByIndex = (arr, idx) => arr.filter(x => x.index !== idx);
// Your data
const json = [{
index: 0,
name: "person 1",
age: 12
},
{
index: 1,
name: "person 2",
age: 19
},
{
index: 2,
name: "person 3",
age: 34
},
];
// Printing the result
console.log(filterByIndex(json, 1));
In your React app
ondeleterow(e: any) {
const columns = this.state.fields.columns.filter(x => x.index !== e.target.id);
this.setState({ fields: { columns }});
}
Try this
onDeleteRow(e) {
const afterRemoval = this.setState.fields.columns.filter(item => item.index != e.target.id);
this.setState(prevState => ({ fields: { ...prevState.fields, columns: afterRemoval } }));
}
The other solution above sets the fields field directly, It may work but will cause problem if fields has some other attribute other than columns (those attributes will get removed)

Array reduce : Sum total of Array length in within another array

I am having difficulty calculating the total votes from the array of choices . I have a json like below
{
id:1,
pollName: 'aaaaa',
pollChoices:[
id: 2,
choice : 'dddd',
votes: [
{
}
]
]
}
I am trying to count the total number votes casted from the jon above within my memoized selectors
My code is like below
const pollChoices: Array<PollChoice> = poll.get("PollChoices").toJS();
const pollStatistic = pollChoices
.reduce((prev: any, curr: any) => {
console.log("The pollStatistic is ", prev);
return { curr, totalVotesCasted: (prev.Votes ?
(prev.Votes.length + curr.Votes.length) :
0 + curr.Votes.length )}
}, {});
console.log("The pollStatistic is ", pollStatistic);
The console within pollStatistic seems to show my totalVotesCasted, however, when i print pollStatistic, its always undefined, i want to be able to get the pollStatistic.totalCount in my state. Pls any help is appreciated.
This is not how reduce works.
You pass the reduce function a reducer callback of this signature: function reducer(accumulator, currentValue, currentIndex) { ... }
The callback should return a the value of the accumulator it wants to be passed to the next iteration.
In your case when you access prev.Votes you should be accessing prev.totalVotesCasted which is the value you set on the accumulator.

Resources