简体   繁体   中英

How to prevent component from updating, if checkbox is checked

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 , then render() 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:

Split the component into 2 sub-components

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.

Demo

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM