客户希望有一个允许他选择数字的数字滑块组件,以及一个显示“无值”的复选框。选中该复选框后,应禁用滑块,但仍应保留其先前选择的配置。
http://image.prntscr.com/image/4efc55b8d11a40749bb1e44c4287a709.png
我在使用具有道具和状态的组件的惯用React方法时遇到了麻烦。
我想把这两个作为单个组件的一部分,一个滑块复选框,带有这样的道具:
value : number
onChange : (newValue : number) => void
现在,如果选中 no value 复选框,则value
未定义。问题是因为value
也设置了滑块的位置,这意味着一旦选中复选框,位置就会改变 - 我不希望这种情况发生。
问题在于React希望保持所有组件同步,在这种情况下,我们不希望让滑块与应用程序的其余部分保持同步。即使value
应该是undefined
(或null
),我们仍然希望滑块位于用户选择的最后一个值上。
解决此问题的正确方法是什么?
答案 0 :(得分:3)
我不知道您的应用程序逻辑是如何工作的,因为您还没有共享它,但是您可以使用shouldComponentUpdate()
来解决此问题。
如果 shouldComponentUpdate 返回
false
,那么render()
将被完全跳过,直到下一次状态发生变化。此外,不会调用componentWillUpdate和componentDidUpdate。
所以你可以这样做:
shouldComponentUpdate(nextProps) {
if(typeof nextProps.value === 'undefined') return false; //return false if value is undefined
return true; //otherwise always return true (this is default)
}
如果value
未定义,这将阻止组件重新呈现。虽然我建议改为发送null
,因为变量实际上是定义的,但根本没有价值。
请注意,这将不按您的要求禁用滑块 - 它只会保持滑块的原始渲染状态。
如果您还想在选中复选框时禁用滑块,那么您可以在此处看到几个选项。这是一个:
这里的想法是道具直接控制滑块和复选框,而不使用state
。如果您想使用 Stateless Functional Components ,这是很棒的,请查看我的指南,了解如何以及为何使用它。
所以你的代码应该是这样的:
<强> 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;
<强>滑块:强>
import React from 'react';
const Slider = (props) => (
<input id="slider" type="range" min="0" max="100" disabled={props.disabled} />
);
export default Slider;
复选框:强>
import React from 'react';
const Checkbox = (props) => (
<input id="checkbox" type="checkbox" onChange={props.onCheckboxChange} />
);
export default Checkbox;
答案 1 :(得分:0)
使用单独的状态来设置滑块输入的值,启用/禁用滑块以及选中/取消选中复选框。以下是一个示例代码段。
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>