Im trying to build a select function for my object. The issue is when I click another element the other elements remain selected.
How can I set all other elements to isSelected: false, after selecting the element I want.
I need a way so that when I set the state of the element I want to true, it will set all other element states to false.
import "./styles.css";
import { useEffect, useState } from "react";
// The parent component
const App = () => {
const [textBoxDivs, setTextBoxDivs] = useState({});
const addNewTextBox = () => {
const numOfTextBoxDivs = Object.keys(textBoxDivs).length;
console.log(numOfTextBoxDivs, "num");
setTextBoxDivs({
...textBoxDivs,
[`div${numOfTextBoxDivs 1}`]: {
isSelected: false,
innerText: "text"
}
});
};
const selectItem = (e) => {
if (e) {
const selectedItemKey = e.target.id;
setTextBoxDivs({
...textBoxDivs,
[selectedItemKey]: {
...textBoxDivs[selectedItemKey],
isSelected: true
}
});
}
};
return (
<div>
<button onClick={() => addNewTextBox()}>
Click me to create a selectable div
</button>
{Object.keys(textBoxDivs).length > 0 &&
Object.keys(textBoxDivs).map((key, index) => {
return (
<div
style={{
border: textBoxDivs[key].isSelected
? "2px solid green"
: "unset"
}}
onClick={(e) => selectItem(e)}
key={index}
id={key}
>
{textBoxDivs[key].innerText}
</div>
);
})}
</div>
);
};
export default App;
codesandbox: https://codesandbox.io/s/friendly-water-wf4f5?file=/src/App.js:0-1385
CodePudding user response:
To start, e
will be defined, so no need to check it.
I would do something like this:
const selectItem = (e) => {
const selectedItemKey = e.target.id;
const nextState = {...textBoxDivs}
Object.keys(nextState).forEach(k => {
nextState[k].isSelected = false
})
nextState[selectedItemKey].isSelected = true
setTextBoxDivs(nextState);
};
I haven't tested this.
CodePudding user response:
I would implement it with a selected
state object, so each div
only needs to check whether or not it's the selected one.
Add a state object to keep track of selected
const [selected, setSelected] = useState();
Change the ternary operator to selected == key ? "2px solid green" : "unset"
. Also, change your onClick
to () => setSelected(key)
<div
style={{
border: selected == key ? "2px solid green" : "unset"
}}
onClick={() => setSelected(key)}
key={index}
id={key}
>
Then remove your selectItem()
function.
Here's the full code:
const App = () => {
const [textBoxDivs, setTextBoxDivs] = useState({});
const [selected, setSelected] = useState();
const addNewTextBox = () => {
const numOfTextBoxDivs = Object.keys(textBoxDivs).length;
console.log(numOfTextBoxDivs, "num");
setTextBoxDivs({
...textBoxDivs,
[`div${numOfTextBoxDivs 1}`]: {
isSelected: false,
innerText: "text"
}
});
};
return (
<div>
<button onClick={() => addNewTextBox()}>
Click me to create a selectable div
</button>
{Object.keys(textBoxDivs).length > 0 &&
Object.keys(textBoxDivs).map((key, index) => {
return (
<div
style={{
border: selected === key ? "2px solid green" : "unset"
}}
onClick={() => setSelected(key)}
key={index}
id={key}
>
{textBoxDivs[key].innerText}
</div>
);
})}
</div>
);
};
export default App;
I think this will make your code more readable, and it reduces the number of lines you'll need to achieve the desired effect by completely removing the need for your selectItem
function.