我无法确定保留原始组件功能的最佳策略(特别是 setSelected(),当使用Redux的connect()
将其包装到更高阶函数时。为我的前端应用程序使用一组很棒的单选按钮组件:
Radio.js
:
class Radio extends React.Component {
constructor(props) {
super(props);
this.state = {selected: props.selected};
}
toggle() {
console.log(this.context)
const {onChange} = this.context.radioGroup;
const selected = !this.state.selected;
this.setState({selected});
// this.props.changeRadioGroupState(this.props.option);
onChange(selected, this);
}
setSelected(selected) {
this.setState({selected});
}
render() {
const activeStyle = {
opacity: 0.1
}
const grayStyle = {
opacity: 0.5
}
let classname = 'form__big_button'
return (
<button type="button"
className={classname}
onClick={this.toggle.bind(this)}
style={this.state.selected ? activeStyle : grayStyle }>
{this.props.option}
</button>
);
}
}
Radio.contextTypes = {
radioGroup: React.PropTypes.object
};
它有一个名为 RadioGroup.js
的父组件:
import React from 'react';
class RadioGroup extends React.Component {
constructor(props) {
super(props);
this.options = [];
this.changeRadioGroupState = this.changeRadioGroupState.bind(this);
}
getChildContext() {
const {name} = this.props;
return {radioGroup: {
name,
onChange: this.onChange.bind(this)
}};
}
changeRadioGroupState(selectedOption){
this.setState({selectedOption: selectedOption});
}
onChange(selected, child) {
console.log(this.options)
this.options.forEach(option => {
if (option !== child) {
option.setSelected(!selected);
}
});
}
render() {
let children = React.Children.map(this.props.children, child => {
let newElement = React.cloneElement(child, {
ref: (component => {this.options.push(component);})
});
return newElement;
});
return <div className="radio-group">{children}</div>;
}
}
RadioGroup.childContextTypes = {
radioGroup: React.PropTypes.object
};
export default RadioGroup;
在一起,它的呈现非常简单:
<RadioGroup>
<Radio id="1" selected={true} option="Opt1"/>
<Radio id="2" selected={false} option="Opt2"/>
</RadioGroup>
但是,我想将Radio
连接到我的Redux商店,以便我可以更新所选的单选按钮:
const mapStateToProps = (state) => {
return {searchType: state.searchType}
}
export default connect(mapStateToProps)(Radio);
然而,这导致浏览器出错:
Uncaught TypeError: option.setSelected is not a function
at eval (RadioGroup.js?6ccb:27)
at Array.forEach (<anonymous>)
at RadioGroup.onChange (RadioGroup.js?6ccb:25)
at Radio.toggle (Radio.js?9dd4:17)
at Object.ReactErrorUtils.invokeGuardedCallback (ReactErrorUtils.js?9efc:71)
at executeDispatch (EventPluginUtils.js?68fe:79)
at Object.executeDispatchesInOrder (EventPluginUtils.js?68fe:102)
at executeDispatchesAndRelease (EventPluginHub.js?daec:43)
at executeDispatchesAndReleaseTopLevel (EventPluginHub.js?daec:54)
at Array.forEach (<anonymous>)
这显然是connect()
组件包裹我的Radio
组件的结果 - 它不再公开setSelected()
函数。使用Redux connect()
函数将原始组件包装在更高阶的组件中时,保留原始组件功能的最佳方法是什么?
我在构造函数中尝试了this.setSelected = this.setSelected.bind(this)
绑定,但看起来connect()
函数返回一个完全不同类型的对象 - Connect
对象。
答案 0 :(得分:3)
当您使用Redux并使用ref时,您应该传递连接选项参数withRef
(这是第四个参数)。
您的连接将如下所示:
export default connect(mapStateToProps, null, null, { withRef: true })(Radio);
然后,您将能够使用以下命令获取组件的功能:
option.getWrappedInstance().setSelected(!selected);
您可以查看react-redux docs here
但我认为这种方法并不是很好,我不建议过度使用refs,也许会尝试将选中的选项作为父RadioGroup
的道具传递,以获得整洁的解决方案。