Below code of incrementing the button. But am facing the issue in the increment function to increment the value.
const [items, setItems] = useState([
{itemName:'item1', quantity:2, isSelected:false},
{itemName:'item2', quantity:5, isSelected:false},
{itemName:'item3', quantity:7, isSelected:false}
]);
const increment = (index) => {
setItems([...items,
index.quantity++
]) }
<button onClick={() => increment(index)}>increment</button>
You are adding an item to the items array instead of editing the desired item, remember that you should also treat state immutably:
const increment = (index) => {
setItems((items) => {
const prevItem = items[index];
return Object.assign([], items, {
[index]: { ...prevItem, quantity: prevItem.quantity + 1 },
});
});
};
Related
I want to create a function that will color the hearts when clicked.
I wrote a function that prints out elements for me, but when I click on any heart, it colors them all.
Where could the problem be?
My code:
const \[userInput, setUserInput\] = useState("");
const \[list, setList\] = useState(\[\]);
const \[hearth, setHearth\] = useState(false);
const \[active, setActive\] = useState(-1);
const handleChange = (e) =\> {
e.preventDefault();
setUserInput(e.target.value);
};
const handleSubmit = (e) =\> {
e.preventDefault();
setList(\[userInput, ...list\]);
setUserInput("");
};
const wishList = (e) =\> {
setHearth(!hearth);
};
useEffect(() =\> {}, \[userInput, list\]);
return (
\<div className="favMusic"\>
<h1>FavMusicList</h1>
\<form\>
\<input value={userInput} onChange={handleChange} type="text" /\>
\<button onClick={handleSubmit}\>Submit\</button\>
\</form\>
<ul className="favMusic__list">
{list.map((i, idx) => {
console.log(idx);
return (
<li key={idx}>
{i}{" "}
<div
id={idx}
onClick={() => wishList(idx)}
className={"hearth" + " " + (hearth ? "true" : "false")}>
<AiOutlineHeart
/>
</div>
</li>
);
})}
</ul>
</div>
I have tried all possible ways from setState to others found on the net but I have no idea how to solve it
Here's a working demo.
Assuming your state data is an array of items, each with its own boolean property indicating whether it's been "liked" by the user:
[
{
id: 1,
liked: true,
title: 'ListItem 1',
},
{
id: 2,
liked: false,
title: 'ListItem 2',
},
// ...
]
Then in your click handler, you'd want to loop over each of the objects to find the item with the corresponding id to change just the boolean property for that one item. For example:
const handleClick = (id) => {
const newLikes = items.map((item) => {
// check the current element's id against the
// id passed to the handler
if (item.id === id) {
// if it matches, update the liked property
// and return the modified object
return { ...item, liked: !item.liked };
}
// if it doesn't match, just return the
// original object
return item;
});
// update state with the new data
setItems(newLikes);
};
my state
const [selectedRows, setSelected] = useState([])
const handleRowClick = useCallback((id) => {
if(selectedRows.includes[id]) {
arr = selectedRows.filter((item) => item !== id) // <==Trying to access the state here
setSelected((prev) => [arr])
} else {
setSelected((prev) => [id])
}
})
Everytime I try to access the selectedRows inside the handleRowClick function it just returns its default value,ie. an empty array
You aren't using a dependency array for useCallback. You probably want this:
const handleRowClick = useCallback((id) => {
if(selectedRows.includes[id]) {
arr = selectedRows.filter((item) => item !== id) // <==Trying to access the state here
setSelected((prev) => [...arr])
} else {
setSelected((prev) => [...id])
}
}, [selectedRows])
Note: notice that I'm destructuring the array so you get a new copy of the array and not an array with just one element.
I'm working with a Material UI stepper wherein each step returns a list of selected items.
In each step, the user can click an item that is highlighted before moving onto the next step.
The results are mapped in a separate component.
const [clicked, setClicked] = useState(undefined);
const selectStyleAndFilter = (item, index) => {
setClicked(index);
selectedItems[activeStep] = item;
};
const handleBack = () => {
setActiveStep(activeStep - 1);
setClicked(undefined);
if (activeStep === 1) {
nextStep(selectedItems).then(products => {
console.log(
'productCount back',
products.data.data.contents.total
);
setActiveStep(activeStep - 1);
setClicked(undefined);
setProductCount(
products.data.data.contents.total === undefined
);
});
}
};
However, when I click the back button to return to the previous step, the item is no longer highlighted.
I tried using the logic from selectStyleAndFilter in the handleBack function to keep the item in state:
const handleBack = (item, index) => {
setActiveStep(activeStep - 1);
setClicked(index);
selectedItems[activeStep] = item;
How can I keep the setClicked state of the previous item applied in the handleBack function?
Convert clicked to be an object that holds the clicked item for each activeStep.
const [clicked, setClicked] = useState({});
The current clicked is derived from the clicked object and activeState
const currentClicked = clicked[activeStep];
When you set the currently clicked item, store it under the activeSet, and maintain the state of the other clicked items:
const selectStyleAndFilter = (item, index) => {
// add the current, but maintain the state of the others
setClicked(c => ({ ...c, [activeStep]: index }));
selectedItems[activeStep] = item;
};
Don't reset the clicked state when moving between steps:
const handleBack = () => {
setActiveStep(activeStep - 1);
if (activeStep === 1) {
nextStep(selectedItems).then(products => {
console.log(
'productCount back',
products.data.data.contents.total
);
setActiveStep(activeStep - 1);
setProductCount(
products.data.data.contents.total === undefined
);
});
}
};
I manage to delete the tasks (you can see it in the console.log) but I don't know how to render the result. I really appreciate your help. Link CodeSanbox: https://codesandbox.io/s/trello-task-forked-2xsh8?file=/src/App.js
const addItem = (e) => {
e.preventDefault();
const item = { id: uuidv4(), content: text };
const requestedColumnId = Object.entries(columns).find(
(i) => i[1].name === "Requested"
)[0];
const column = columns[requestedColumnId];
setColumns({
...columns,
[requestedColumnId]: {
...column,
items: [...column.items, item]
}
});
setText("");
};
const deleteItem = id => {
const requestedColumnId = Object.entries(columns).find(
(i) => i[1].name === "Requested"
)[0];
const column = columns[requestedColumnId];
const arrFiltered = column.items.filter(item => item.id !== id)
console.log('arrFiltered', arrFiltered)
setColumns({
...columns,
[requestedColumnId]: {
...column,
items: [...column.items]
}
});
}
Here is a straight forward solution. You did it everything correctly but you missed something. Just update your delete function to the following
const deleteItem = (id) => {
const requestedColumnId = Object.entries(columns).find(
(i) => i[1].name === "Requested"
)[0];
const column = columns[requestedColumnId];
setColumns({
...columns,
[requestedColumnId]: {
...column,
items: [...column.items.filter((item) => item.id !== id)]
}
});
};
Your mistake is that you're filtering the array upon deletion. But you're not updating the main item. So I solved it by adding the array filter in to the main item and removing your filter. Just like this.
setColumns({
...columns,
[requestedColumnId]: {
...column,
items: [...column.items.filter((item) => item.id !== id)]
}
});
Im new to programming, just a junior for now.
I have list of checkboxes. And when I uncheck a checkbox, I want unchecked checkbox to be saved in my local storage. Here is my code snipped, what im doing wrong? Cant fully understand what i wrote. Thank you
export default () => {
const [isDefaultChecked, setDefaultChecked] = useState(true);
const [isChecked, setChecked] = useState();
const [isColumn, setColumn] = useState(true);
const [hiddenColumns, setHiddenColumns] = useState([]);
const [Checked, setIsChecked] = useState([]);
const onCheckboxChange = (key: string, value: boolean) => {
const array = JSON.parse(localStorage.getItem("hiddenColumns"));
// here im trying to check if value = to
if (value) {
const column = hiddenColumns.find((item) => item.value == key);
const filtered = hiddenColumns.filter(
(item) => item.key !== column.key
)
setHiddenColumns(filtered);
if (!value) {
setHiddenColumns([...hiddenColumns, { 'label': key } ]);
}
localStorage.setItem("hiddenColumns", JSON.stringify(key));
}
};
return(
<div>
<Checkbox
defaultChecked={isDefaultChecked}
label="Delivery Methods"
onChange={(value) => onCheckboxChange("delieveryMethods", value)}
/>
</div>
)
if (!value) {
setHiddenColumns([...hiddenColumns, { 'label': key } ]);
}
localStorage.setItem("hiddenColumns", JSON.stringify(key));
You are saving a single key to localStorage, to be consistent with your code, you must save the entire array again.
Now, you hiddenColumns array seems to be a collection of { label } where label is the key.
Also, it stores the values that are hidden only. So, on your onCheckboxChange, if value is true, it means that you should add the key of the checkbox to the array and if value is false, you should take it out. The following codes achieves that
const onCheckboxChange = (key: string, value: boolean) => {
if (value) setHiddenColumns(hiddenColumns => [...hiddenColumns, { label: key }]);
else setHiddenColumns(hiddenColumns.filter(x => x.label !== key));
};
after that, you can add a useEffect hook that would be triggered when hiddenColumns array changes that would maintain your localStorage sync with hiddenColumns array
React.useEffect(() => {
localStorage.setItem("hiddenColumns", JSON.stringify(hiddenColumns));
}, [hiddenColumns]);