Redux connect()删除了我的组件所需的功能

时间:2018-04-04 05:04:38

标签: javascript reactjs redux

我无法确定保留原始组件功能的最佳策略(特别是 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对象。

1 个答案:

答案 0 :(得分:3)

当您使用Redux并使用ref时,您应该传递连接选项参数withRef(这是第四个参数)。 您的连接将如下所示: export default connect(mapStateToProps, null, null, { withRef: true })(Radio);

然后,您将能够使用以下命令获取组件的功能: option.getWrappedInstance().setSelected(!selected);

您可以查看react-redux docs here

但我认为这种方法并不是很好,我不建议过度使用refs,也许会尝试将选中的选项作为父RadioGroup的道具传递,以获得整洁的解决方案。