Basically, I have several buttons. I want the user to be able to have multiple buttons selected.
I tried using a functional component and storing the button state as an object with the useState hook. The state updates accordingly when the buttons are clicked, but the button's props do not update. I've tried useEffect to rerender the component when props.isActive changes but that did not work.
Using a class component, this works exactly as intended. I'm just trying to understand why that is the case. If anyone can provide insight, I would greatly appreciate it. Thanks.
Functional Component
const View = (props) => {
var [buttons, setButtons] = useState([
{ name: "Small", isActive: false },
{ name: "Large", isActive: false },
]);
const handleClick = (index) => {
let tmp = buttons;
tmp[index].isActive = !tmp[index].isActive;
return setButtons(tmp);
};
return (
<div>
{buttons.map((e, index) => {
return (
<MyButtonComponent
key={index}
name={e.name}
isActive={e.isActive}
onClick={() => handleClick(index)}
/>
);
})}
</div>
);
};
Class Component
class View extends Component {
state = {
btn: [
{ name: "Small", isActive: false },
{ name: "Large", isActive: false },
],
};
handleClick = (index) => {
let tmp = this.state.btn;
tmp[index].isActive = !tmp[index].isActive;
return this.setState({ ...this.state, btn: tmp });
};
render() {
return (
<div>
{this.state.btn.map((e, index) => {
return (
<MyButtonComponent
key={index}
name={e.name}
isActive={e.isActive}
onClick={() => this.handleClick(index)}
/>
);
})}
</div>
);
}
}
You are mutating your old array, and then setting state with the mutated array. This is not a good idea in react, regardless of whether you're using class components or function components. The class component let you get away with it, but the function component compares the state before with the sate after and sees that they're the same array, so it skips rendering.
To fix this, you should create a new state instead of mutating the old. Change this:
let tmp = buttons;
tmp[index].isActive = !tmp[index].isActive;
return setButtons(tmp);
To this:
// Create a copy of the array
let tmp = [...buttons];
// Also copy the item you want to change
tmp[index] = {
...tmp[index],
active: !tmp[index].active
}
setState(tmp);
You're updating the reference and setting the same reference to the state (setButtons(tmp))
, which react thinks
, array didn't change because of shallow comparison. You need use new reference. Like the following
let tmp = buttons; <-- problem is here, reference
tmp[index].isActive = !tmp[index].isActive;
return setButtons(tmp); <-- and updating same `reference`
const handleClick = (index) => {
buttons[index].isActive = !buttons[index].isActive;
return setButtons([...buttons]); <-- this will work
};
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.