how to update nested state in reactjs, such as I have an Array of an object of course
state = {
courses: [
{ id: 1, coursename: "CSS3", like: 25, dislike: 0 },
{ id: 2, coursename: "Javascript", like: 45, dislike: 0 },
{ id: 3, coursename: "ReactJS", like: 294, dislike: 0 }
]
};
now i want to update like on the particular course only on onClick , after updating it should be 26 . and again if i click it should decremented by 1.
You can find the code in codesandbox
In your handleLike method, you can map the courses and update the like field of the given course like this:
handleLike = id => {
console.log("id", id);
const updatedCourses = this.state.courses.map(c => {
if (c.id === id) {
return {
...c,
like: c.like + 1
};
} else {
return c;
}
});
this.setState({
courses: updatedCourses
});
};
Related
Basically i want to select an emoji from an array which contains objects (id, name, count) and if i select an item on the array i want to increase its value and if i deselct it i want to decrease its value
for now i've done this which basically increase the value of an item in the array, please help me, thanks.
this is the array
const [emojisArr, setEmojisArr] = React.useState([
{
name: 'like',
emoji: '👍',
count: 11,
},
{
name: 'heart',
emoji: '❤️',
count: 21,
},
{
name: 'joy',
emoji: '😂',
count: 31,
},
{
name: 'fire',
emoji: '🔥',
count: 34,
},
{
name: 'star',
emoji: '💯',
count: 5,
},
]);
and this is the function when i click on the button
const likePost = item => {
const index = emojisArr.findIndex(emoji => emoji.name === item);
emojisArr[index].count += 1;
setEmojisArr(old => [...old]);
}
Set this code see below. you can pass action (selected/deselected) as string. so, it can increment/decrement count on the behalf of action.
const post = (item, action) => {
const newState = emojisArr.map((emoji) => {
if (emoji.name === item) {
return {
...emoji,
count: action === "selected" ? emoji.count + 1 : emoji.count - 1
};
}
return emoji;
});
setEmojisArr(newState);
};
I am trying to use update state in a react function component but it is not working. I tried following a tutorial on pluralsite and apply it to my own project. Ideally this code should be finding the product based on the ID number and replacing the total with a new value.
Unfortunately I am getting an error saying that 'productData.find' is not a function and I'm not sure where the code being used for that is. Are there any suggestions on how to solve this issue?
This is what the data looks like. In this example I am saving the first element of the array.
export let data = [
{
name: "Name",
description:
"",
products: [
{
id: 1,
name: "Name 1",
material: 1.05,
time: 25,
total: 0,
},
{
id: 2,
name: "Name 2",
material: 3,
time: 252,
total: 0,
},
],
},
...
];
function CompareCard({}) {
const index = 0;
const [productData, setProductData] = useState(data[index]);
function setTotalUpdate(id) {
const productPrevious = productData.find(function (rec) {
return rec.id === id;
});
const productUpdated = {
...productPrevious,
total: 1,
};
const productNew = productData.map(function (rec) {
return rec.id === id ? productUpdated : rec;
});
setProductData(productNew);
}
setTotalUpdate(1)
}
It's because productData is not an array so .find would not work. You want iterate over the products property in your data, so do productData.products.find(...)
When you do
const [productData, setProductData] = useState(data[index])
you don't pass an Array on your state but an Object (the first element of your data so an Object) and Object don't have find method.
Try
const [productData, setProductData] = useState([data[index]])
with [] on our useState to put your Object on array
///////////////////////////////// Edit /////////////
Ok, I try your code, and I propose you this.
import React, { useState } from "react";
const data = [
{
name: "Name",
description: "",
products: [
{
id: 1,
name: "Name 1",
material: 1.05,
time: 25,
total: 0,
},
{
id: 2,
name: "Name 2",
material: 3,
time: 252,
total: 0,
},
],
},
];
const CompareCard = () => {
// setState with the subArray products from data[0], I use '...' (spread operator) inside a Array or an Object to make a shalow copy
const [productsData, setProductsData] = useState([...data[0].products]);
const setTotalUpdate = (id) => {
// find the product to change inside products collection, that's ok
const productPrevious = productsData.find((rec) => {
return rec.id === id;
});
// create a new product to change one property's value, you can do something like 'productPrevious.total = 1', same same
const productUpdated = {
...productPrevious,
total: 1,
};
// create a new products collection to update state
const productNew = productsData.map((rec) => {
return rec.id === id ? productUpdated : rec;
});
setProductsData([...productNew]);
};
const setTotalUpdateSecond = (id) => {
// create a newState
const newState = productsData.map((product) => {
// condition if id === productId and do something
if (id === product.id) {
product.total = 1;
}
// both case, I return the product (change or not)
return product;
});
setProductsData([...newState]);
};
return (
<>
<button onClick={() => setTotalUpdate(1)}>Test old method on product 1</button>
<button onClick={() => setTotalUpdateSecond(2)}>Test second method on product 2</button>
{productsData.map((product) => {
return (
<>
<p>Product Id : {product.id} / Product Total : {product.total}</p>
</>
);
})}
</>
);
};
export default CompareCard;
Can you copy / past this, try and say me if it's what you want, if yes, I explain you where the confusion was. If not, explain me, what's the problem here and I modificate.
I tried with the below code but it is executing on the second attempt, I want to execute Alert on the Dropdown function, I am not rendering returnCount just using it to display an alert,
anyone knows the answer plz answer this, don't send any link, nothing is working out instead please write the answer
const [arrayList, setArrayList] = useState([
{ Id: 1, Name:'A', ItemDeliveryStatus:4 },
{ Id: 2, Name:'B', ItemDeliveryStatus:4 },
{ Id: 3, Name:'C', ItemDeliveryStatus:4 },
{ Id: 4, Name:'D', ItemDeliveryStatus:4 },
])
const [returnCount ,setReturnCount ]=useState(0)
//function on the picker, want to update returnCount immediately so that I can use it for below alert
function displayalertBox(){
arrayList.map(items =>
{
if(items.ItemDeliveryStatus=='4')
{
setReturnCount(prev=> prev+1)
}
})
if(returnCount==4)
{
alert('alert as returncount is equal to 4')
}
}
You need to do the desired functionality inside of an useEffect when using react hooks.
const [arrayList, setArrayList] = useState([{
Id: 1,
Name: 'A',
ItemDeliveryStatus: 4
},
{
Id: 2,
Name: 'B',
ItemDeliveryStatus: 4
},
{
Id: 3,
Name: 'C',
ItemDeliveryStatus: 4
},
{
Id: 4,
Name: 'D',
ItemDeliveryStatus: 4
},
])
const [returnCount, setReturnCount] = useState(0)
function displayalertBox() {
arrayList.map(items => {
if (items.ItemDeliveryStatus == '4') {
setReturnCount(prev => prev + 1)
}
})
}
// You cantry this too if needed.
function displayalertBox1() {
arrayList.map(items => {
if (items.ItemDeliveryStatus == '4') {
let count
setReturnCount(prev => {
count = prev + 1;
//since state update is guaranteed, you can try this too.
if (count === 4) {
alert('alert as returncount is equal to 4')
}
return count
})
}
})
}
useEffect(() => {
if (returnCount == 4) {
alert('alert as returncount is equal to 4')
}
}, [returnCount]);
Hi friends,
I'm getting a little trouble putting that to work.
This method intend to put check if there's a product in the cart, if true, sum the same product.
onAddProductToCart = (productId) => {
const productInCart = this.state.productsInCart.find(
(product) => productId === product.id
);
if (productInCart) {
const newProductsInCart = this.state.productsInCart.map(product => {
if(productId === product.id) {
return {
...product,
quantity = product.quantity + 1
}
}
return product
})
this.setState({productsInCart: newProductsInCart})
}
};
I'm getting this error point to my assignment "=" bellow
Parsing error unexpected token:
quantity = product.quantity + 1
This method is inside the App class component , with has some mocked data.
class App extends Component {
state = {
minFilter: "100",
maxFilter: "2000",
nameFilter: "Produto",
productsInCart: [
{
id: 3,
name: "Produto 3",
price: 300.77,
photo: "https://picsum.photos/200/200?a=3",
quantity: 1,
},
{
id: 4,
name: "Produto 4",
price: 400,
photo: "https://picsum.photos/200/200?a=4",
quantity: 2,
},
],
};
You have to use colon : when set a object property
return {
...product,
quantity:product.quantity + 1
}
Using a colon would do the trick
quantity: product.quantity + 1
I want to update a state (data) that depends on other calculated state (server)
setServer(prevTweets =>
[...json, ...prevTweets].filter(
(e, i, arr) => i === arr.findIndex(t => t.tweetId === e.tweetId)
)
)
The data above will be used to set the state below (data) :
let totalPositive = 0;
let totalNegative = 0;
let totalNeutral = 0;
server.forEach(tweet => {
if(tweet.sentiment >0) totalPositive++;
if(tweet.sentiment < 0) totalNegative++;
if(tweet.sentiment ===0) totalNeutral++;
})
setData([
{ name: 'Positive', value: totalPositive },
{ name: 'Negative', value: totalNegative },
{ name: 'Neutral', value: totalNeutral },
])
Since it's asynchronous, the setData operation is always late. I know that I can use useEffect but apparently it will make an infinite loop and it's not right to use it in this case.
If you set the new data before you set the server you'd skip one render:
//still defaults to server so if you do't pass anything it;s still the same
const setNewData = (newServer = server) => {
const [
totalPositive,
totalNegative,
totalNeutral,
] = newServer.reduce(
([pos, neg, neu], { sentiment }) =>
sentiment > 0
? [pos + 1, neg, neu]
: sentiment < 0
? [pos, neg + 1, neu]
: [pos, neg, neu + 1],
[0, 0, 0]
);
setData([
{ name: 'Positive', value: totalPositive },
{ name: 'Negative', value: totalNegative },
{ name: 'Neutral', value: totalNeutral },
]);
};
setServer(prevTweets => {
const newServer = uniqueByTweetId([
...json,
...prevTweets,
]);
setNewData(newServer);
return newServer;
});
Unrelated to the question but could be important is that the way you get unique values could be improved. You could get unique values in one pass without having to call find index many times:
const uniqueBy = getter => arr => {
const items = new Map();
return arr.filter(item => {
const key = getter(item);
const ret = items.get(key);
items.set(key,true);
return !ret;
});
};
const data = [
{ id: 1 },
{ id: 2 },
{ id: 3 },
{ id: 4 },
{ id: 5 },
{ id: 1 },
{ id: 7 },
{ id: 1 },
{ id: 7 },
{ id: 8 },
{ id: 1 },
];
const uniqueById = uniqueBy(i => i.id);
console.log(uniqueById(data));