'In react how to update state when checkbox is disabled
Situation
I have a semi complex form implemented in react in which ticking certain checkboxes will lead to other checkboxes being enabled/disabled. This all works fine, but if a disabled tickbox was previously ticked then its state remains even though the UI is showing it unticked. For example
This state is created by first ticking A so B becomes available, ticking B, then unticking A. This leaves a ghost state for tickbox B
Minimal example
Here is a simplified example of my depentant tick boxes. Note that tickbox B unticks itself in the UI if tickbox A is unticked. But handleToggleTickBoxB is not called when this happens to update the underlying state.
const e = React.createElement;
class ReactGameForm extends React.Component {
constructor(props) {
super(props);
this.state = {
tickBoxA:false,
tickBoxB:false
};
}
handleToggleTickBoxA = (event) => {
this.setState({tickBoxA: event.target.checked})
}
handleToggleTickBoxB = (event) => {
this.setState({tickBoxB: event.target.checked})
}
render() {
return <form>
<div className="form-check">
<input className="form-check-input" type="checkbox" name="platformRadios" value="A" id="tickboxA" checked = {this.state.tickBoxA} onChange={event => this.handleToggleTickBoxA(event)} />
<label className="form-check-label" htmlFor="tickboxA">
<b>Tick Box A</b>
</label>
</div>
<div className="form-check">
<input disabled = {!this.state.tickBoxA} className="form-check-input" type="checkbox" value="B" id="tickboxB" checked = {this.state.tickBoxA && this.state.tickBoxB} onChange={event => this.handleToggleTickBoxB(event)} />
<label className="form-check-label" htmlFor="tickboxB">
<b>Tick Box B</b>
</label>
</div>
<p>Tick box A: {this.state.tickBoxA && <span>Ticked</span>}</p>
<p>Tick box B: {this.state.tickBoxB && <span>Ticked</span>}</p>
</form>
}
}
$(document).ready(function () {
const domContainer = document.querySelector('#react_game_form');
ReactDOM.render(e(ReactGameForm), domContainer);
})
This causes all sorts of complexity further down the line where other bits of UI think tickbox B is ticked.
Question
What is the proper way to ensure that state dependant disabling is propagated so that the state of that tickbox is reflected in the react state
Notes
In the real example this is a list of libraries which have relatively complex rules as to if they are available. Its not as simple as A -> B. It might be "B requires any 1 of A1 A2 or A3 but must not have A4"
Solution 1:[1]
In the end I realised I was doing too much state calculation in the render() itself, and moved the equivalent to the "untick tickboxB" into handleToggleTickBoxA itself. Then the state and UI remained in sync.
So my self answer would be that this is what I should have done:
const e = React.createElement;
class ReactGameForm extends React.Component {
constructor(props) {
super(props);
this.state = {
tickBoxA:false,
tickBoxB:false
};
}
handleToggleTickBoxA = (event) => {
this.setState({tickBoxA: event.target.checked, tickBoxB: event.target.checked && this.state.tickBoxB })
}
handleToggleTickBoxB = (event) => {
this.setState({tickBoxB: event.target.checked})
}
render() {
return <form>
<div className="form-check">
<input className="form-check-input" type="checkbox" name="platformRadios" value="A" id="tickboxA" checked = {this.state.tickBoxA} onChange={event => this.handleToggleTickBoxA(event)} />
<label className="form-check-label" htmlFor="tickboxA">
<b>Tick Box A</b>
</label>
</div>
<div className="form-check">
<input disabled = {!this.state.tickBoxA} className="form-check-input" type="checkbox" value="B" id="tickboxB" checked = {this.state.tickBoxB} onChange={event => this.handleToggleTickBoxB(event)} />
<label className="form-check-label" htmlFor="tickboxB">
<b>Tick Box B</b>
</label>
</div>
<p>Tick box A: {this.state.tickBoxA && <span>Ticked</span>}</p>
<p>Tick box B: {this.state.tickBoxB && <span>Ticked</span>}</p>
</form>
}
}
$(document).ready(function () {
const domContainer = document.querySelector('#react_game_form');
ReactDOM.render(e(ReactGameForm), domContainer);
})
Solution 2:[2]
Firstly you need to add a reference to Serilog.Sinks.File via nuget.
The next step is to add the destination for Logger:
.WriteTo.File(new JsonFormatter(), "log.json")
The full listing is:
Log.Logger = new LoggerConfiguration()
.WriteTo.File(new JsonFormatter(), "log.json")
.CreateLogger();
Log.Information("No one listens to me!");
// Finally, once just before the application exits...
Log.CloseAndFlush();
The output in log.json file is:
{"Timestamp":"2022-01-14T02:49:31.5111479+00:00","Level":"Information","MessageTemplate":"No one listens to me!"}
Is it what you need?
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Richard Tingle |
| Solution 2 | Georgy Tarasov |

