A client wants to have a numeric slider component that lets him select a number, and a checkbox that says 'no value'. When the checkbox is checked, the slider should be disabled but should still retain its previously selected configuration.
http://image.prntscr.com/image/4efc55b8d11a40749bb1e44c4287a709.png
I'm having trouble implementing this using the idiomatic React way, of Components that have props and state.
I'm envisioning the two as part of a single component, a slider-checkbox, with props like this:
value : number
onChange : (newValue : number) => void
Now, if the no value checkbox is checked, then value
is undefined. The problem is that because value
also sets the position of the slider, this means the position will be changed once the checkbox is ticked -- and I don't want that to happen.
The problem is while React wants to keep all the components in sync, in this case we don't want to keep the slider in sync with the rest of the application. Even though the value
should be undefined
(or null
), we still want the slider to be sitting on the last value the user picked.
What is the correct way to resolve this issue?
I don't know how your application logic works, since you haven't shared it, however you could use shouldComponentUpdate()
to resolve this issue.
If shouldComponentUpdate returns
false
, thenrender()
will be completely skipped until the next state change. In addition, componentWillUpdate and componentDidUpdate will not be called.
So you could do:
shouldComponentUpdate(nextProps) {
if(typeof nextProps.value === 'undefined') return false; //return false if value is undefined
return true; //otherwise always return true (this is default)
}
This will prevent the component from re-rendering if value
is undefined. Though I would suggest sending in null
instead, since the variable is actually defined, but has simply no value.
Note that this will not disable the slider as you requested - it will simply maintain the original render-state of the slider.
If you also want to disable the slider when the checkbox is checked, you have a couple of options here as I see it. Here's one:
The idea here is that the props control the slider and checkbox directly, without the use of a state
. This is great if you want to use Stateless Functional Components , check out my guide on how and why to use that.
So your code would be something like:
CheckboxSlider:
class CheckboxSlider extends React.Component {
constructor(props, context) {
super(props, context);
this.state = {
value: 50, //default is in the middle, 50%
disabled: false
};
}
_toggleSlider = () => {
this.setState({disabled: !this.state.disabled});
}
render() {
<div>
<Slider value={this.state.value} disabled={this.state.disabled} />
<CheckBox onCheckboxChange={this._toggleSlider} />
</div>
}
}
export default CheckboxSlider;
Slider:
import React from 'react';
const Slider = (props) => (
<input id="slider" type="range" min="0" max="100" disabled={props.disabled} />
);
export default Slider;
Checkbox:
import React from 'react';
const Checkbox = (props) => (
<input id="checkbox" type="checkbox" onChange={props.onCheckboxChange} />
);
export default Checkbox;
Use separate state to have value of slider input, to enable/disable the slider and to check/uncheck the checkbox. Below is a sample snippet.
class Slider extends React.Component { constructor(props) { super(props) this.state = { sliderValue: 100, checkedValue: false, enable: false } } handleChange= (e) => { this.setState({sliderValue: e.target.value}); } handleClick = (e) => { if(this.state.checkedValue == false) { this.setState({checkedValue: true, enable: true}, function() { this.refs.slider.disabled = true; }.bind(this)); } else if(this.state.checkedValue == true) { this.setState({checkedValue: false, enable: false}); } } render() { return ( <div> <input type="range" ref="slider" value={this.state.sliderValue} onChange={this.handleChange} min="100" max="500" step="10" disabled={this.state.enable}/> <input type="checkbox" onChange={this.handleClick} /> </div> ) } } ReactDOM.render(<Slider />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.14.8/react-dom.min.js"></script> <div id="app"></div>
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.