Fix #416 : Checkbox isSelected state toggles internally#501
Conversation
| if (this.props.isSelected !== isSelected) { | ||
| this.setState({ isSelected }) | ||
| } | ||
| getIsSelected() { |
There was a problem hiding this comment.
This changes the API contract for every RadioCheckboxBase consumer, not just Checkbox. Before this patch, passing isSelected={false} still allowed the component to toggle internally after mount. With getIsSelected() treating any defined isSelected as controlled, isSelected={false} now freezes the visual state unless the parent writes the new value back on every onChange. That is a breaking behavior change for existing Radio/Switch/Checkbox usages built around the previous semantics. If the goal is only to fix the controlled-checkbox sync bug, this needs a narrower compatibility strategy or an explicit API change.
| expect(wrapper.find('input').instance().checked).toBe(true) | ||
| }) | ||
|
|
||
| it('acts as controlled when isSelected prop is provided', () => { |
There was a problem hiding this comment.
The new coverage only exercises the controlled case with isSelected={true}. The regression-prone case here is isSelected={false}, because that is the scenario that now changes behavior from "starts unchecked, then toggles internally" to fully controlled/non-toggling. Please add a test for isSelected={false} so this contract change is either caught or made explicit.
78fff08 to
3fcf61a
Compare
Fixes #416.
This PR resolves an issue where the
Checkboxcomponent (built onRadioCheckboxBase) was maintaining its own internal state (this.state.isSelected) and toggling it immediately on click, even when acting as a controlled component (whereisSelectedis supplied as a prop).This local state mutation caused synchronization bugs when the parent component chose not to update the prop on
onChange(e.g. while awaiting popup confirmation), leaving the checkbox visually unchecked whileisSelected={true}was still passed.Solution
isSelectedis provided by the parent, it is treated as controlled and serves as the single source of truth (getIsSelected()). Clicking does not change the visual state internally unless the parent updates the prop.isSelectedis omitted, it behaves as uncontrolled and falls back to a local state (localIsSelected) that toggles on click.componentWillReceivePropsmethod which was previously attempting to sync state from props incorrectly.