find a specifik obejct with arrays and print it out, react - reactjs

I want to use find when clicking a button, I want to find an obejct (working in react)
let numbers = [
{ id: 0, namn: one, img: "../number/one" },
{ id: 1, namn: two, img: "../number/two" },
{ id: 2, namn: three, img: "../number/three" },
];
const [selected, setSelected] = useState({
id: 0,
name: "one",
img: "../number/one",
});
const count = useRef(0);
function next() {
if (count.current === 2) {
count.current = 0;
let found = numbers.find((number) => number.id === count.current);
} else {
count.current = count.current + 1;
let foundtwo = numbers.find((number) => number.id === count.current);
}
return (
<>
<img>{selected.img}</img>
namn: {selected.name}
</>
);
}
I can find it but I want to put it in a useState.
or somehow get it to show. how can I get found, and found two out in the return

the awswer was to put a
if( found === undefined){
console.log("error")
}else{
setSelected(found)
}

Related

Replacing value in nested state with react functional components

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.

State not updating in react with a nested object (hooks)

I've been playing with react-beautiful-dnd and hooks (very new to react) - and for some reason my state doesn't update on drag. (Edit: I know the logic only works for 'same category' drag - this isn't updating the UI either for me)
Data (simplified)
const skills = {
skills: {
skill1: {
id: "skill1",
name: "Communication"
},
skill2: {
id: "skill2",
name: "Empathy"
},
skill3: {
id: "skill3",
name: "Initiative"
}
},
categories: {
cat1: {
id: "cat1",
name: "Core",
skillIds: ["skill1", "skill2", "skill3", "skill4"]
},
cat2: {
id: "cat2",
name: "Craft",
skillIds: ["skill5", "skill6", "skill7", "skill8"]
},
cat3: {
id: "cat3",
name: "Leadership",
skillIds: ["skill9", "skill10"]
}
},
categoryOrder: ["cat1", "cat2", "cat3"]
};
Function to update the skillIds array in the correct category
const reorder = (list, startIndex, endIndex) => {
const result = Array.from(list);
const [removed] = result.splice(startIndex, 1);
result.splice(endIndex, 0, removed);
return result;
};
const onDragEnd = (result) => {
const { source, destination } = result;
// dropped outside the list
if (!destination) {
return;
}
// Handle moving within one category
if (source.droppableId === destination.droppableId) {
const catSkills = data.categories[source.droppableId].skillIds;
const items = reorder(catSkills, source.index, destination.index);
const newData = {
...data,
categories: {
...data.categories,
[source.droppableId]: {
...data.categories[source.droppableId],
skillIds: items
}
}
};
setData(newData);
}
};
I've created a simplified codesandbox to test - https://codesandbox.io/s/hooks-problem-il5m4
Any help appreciated!
I can see the state is getting updated
if (source.droppableId === destination.droppableId) { setData(data) }
this "if" clause means it will only update the state if the drag is happen on the same lane .i think you have tried to drag it to another lane . hope this is what you meant
Edit: I have understood your problem . The issue is you are not using updated data you are looping the static skill.I hope this solve your problem
{data.categoryOrder.map((catId) => {
const category = data.categories[catId]; //change skills to data
const catSkills = category.skillIds.map(
(skillId) => skills.skills[skillId]
);

Change variable in array of objects in state React

What I wanted to do is whenever I click button to change variable in states array of objects. I did it this way, but is there any easier way to do it?
completeItem = (id) => {
const item = this.state.items.filter(el =>{
return el.id === id;
});
item[0].isCompleted = true;
const state = this.state.items;
const arr = this.state.items.filter(el =>{
if(el.id === id){
state[id-1] = item[0];
}
return state;
});
this.setState({
items:[...arr],
});
}
Try this solution...
completeItem = (id) => {
const items = this.state.items.filter(el =>{
if(el.id === id){
el.isCompleted = true;
}
return el;
});
this.setState({
items : [...items],
});
}
If the solution is helpful please let me know!
May compromise a little performance, but it is more readable.
completeItem = (id) => {
const newList = [...this.state.items]
const index = newList.findIndex(el => el.id === id);
newList[index].isCompleted = true
this.setState({ items: newList });
}
Here is how you can do it:
const items = [{
id: 1,
name: "one",
isCompleted: false
},
{
id: 2,
name: "two",
isCompleted: false
},
{
id: 3,
name: "three",
isCompleted: false
},
{
id: 4,
name: "four",
isCompleted: false
}
]
completeItem = (id) => {
const result = items.map(e => {
if (e.id === id) {
return { ...e,
isCompleted: true
}
} else {
return e;
}
});
console.log(result)
}
completeItem(2)

Update state that depends on other calculated state in React-Hooks

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));

Update item in state onClick ReactJS

So, I have class Comopnent :
state = {
tokens: [
{
name: "first",
value: 3
},
{
name: "second",
value: 2
},
{
name: "third",
value: 4
}
]
}
handleClick = (name, id) => {
const newState = this.state.tokens.map((token => {
console.log(token.name)
}))
}
render() {
const token = this.state.tokens;
const tokenList = token.map(t => {
return (
<div value={t.name} onClick={() => this.handleClick(t.name, t.value)}>
<img src=""/>
</div>
)
})
What i need to do - after click - to subtract 1 from value clicked token.
So - ex. after click on "First" token i want his value equal 2.
So far I've done just as much as the above.
I do not know how to go about it, i am new in ReactJS, so thanks for help in advance!
You'll have to find in your state in tokens array the object which has the same name as the argument passed in the onclick handler. Then you will have to change it's value - decrement it (value--) but you have to be aware that you can't mutate the state.
handleClick = name => () => {
const { tokens } = this.state;
const clickedToken = tokens.find(token => token.name === name);
clickedToken.value--;
const clickedTokenIndex = tokens.indexOf(clickedToken);
const newTokens = [
...tokens.slice(0, clickedTokenIndex),
clickedToken,
...tokens.slice(clickedTokenIndex + 1)
];
this.setState({ tokens: newTokens });
};
Codesandbox link: https://codesandbox.io/s/92yz34x97w
First, some things are wrong with your code.
1- You have an array of tokens, then you're mapping the list, but you don't have a key to index, this will cause weird behaviors, I improve your tokens list with keys now.
2.- You can handle the click and change the state of the tokens list, this will trigger a reload of the component.
state = {
tokens: [
{
name: "first",
value: 3,
id: 1
},
{
name: "second",
value: 2,
id: 2
},
{
name: "third",
value: 4,
id: 3
}
]
}
handleClick = (name, id) => {
const { tokens} = this.state;
const newState = tokens.map((token => {
if(token.id === id) {
token.value--;
}
return token;
}))
}
render() {
const token = this.state.tokens;
const tokenList = token.map(t => {
return (
<div key={t.key} value={t.name} onClick={() => this.handleClick(t.name, t.value, t.key)}>
<img src=""/>
</div>
)
})

Resources