无法通过ref访问子功能?

时间:2017-02-03 13:28:01

标签: reactjs redux react-redux

最初一切都运转良好,我有一个类似的组件。 此

  class A extends React.Component {
     constructor(props) {
       super(props);
       this.childRef = null
     }

    componentDidMount() {
     this.childRef = this.refs.b
     // now I can call child function like this
      this.childRef.calledByParent()
    }

    render(){
      <B ref = "b"/>
    }
  }

在其他档案中

     class B extends React.Component {

       calledByParent(){
         console.log("i'm called")
        }

       render(){
        <div> hello </div>
       }
  }
 export default B

直到这里工作正常,但是当我在class B export default connect(mapStateToProps, mapDispatchToProps)(B)

中执行此类操作时

它不起作用。我从react-redux

导入了connect

3 个答案:

答案 0 :(得分:9)

connect()接受option作为第四个参数。在此选项参数中,您可以将标志withRef设置为true。在此之后,您可以使用getWrappedInstance()之类的

来访问要引用的函数
class A extends React.Component {
     constructor(props) {
       super(props);
       this.childRef = null
     }

    componentDidMount() {
        this.childRef.getWrappedInstance().calledByParent()
    }

    render(){
      <B ref = {ref => this.childRef = ref}/>
    }
  }

class B extends React.Component {

       calledByParent(){
         console.log("i'm called")
        }

       render(){
        <div> hello </div>
       }
  }
   export default  connect(mapStateToProps, mapDispatchToProps, null, {withRef: true})(B)

答案 1 :(得分:3)

我有类似的问题,但我不想让我的API依赖getWrappedInstance()次调用。实际上,类层次结构中的某些组件可能使用connect()并访问存储,而其他组件只是无状态组件,不需要额外的Redux层。

我刚写了一个小的(可能有点hackish)方法。请注意,它尚未经过全面测试,因此您可能需要进行一些调整才能使其在您自己的场景中正常运行。

TypeScript(应该很容易转换为纯JavaScript语法):

function exposeWrappedMethods(comp: React.ComponentClass<any>, proto?: any): any {
    if (!proto) {
        if (comp.prototype.constructor.name === 'Connect') {
            // Only Redux component created with connect() is supported
            proto = comp.prototype.constructor.WrappedComponent.prototype;
        } else {
            console.warn('Trying to extend an invalid component.');
            return comp;
        }
    }

    let prototypeName: string = proto.constructor.name;
    if (prototypeName.search(/^React.*Component.*/) < 0 && proto.__proto__) {
        for (let propertyName of Object.getOwnPropertyNames(proto)) {
            if (!comp.prototype[propertyName]) {
                let type: string = typeof proto[propertyName];
                if (type === 'function') {
                    // It's a regular function
                    comp.prototype[propertyName] = function (...args: any[]) {
                        return this.wrappedInstance[propertyName](args);
                    };
                } else if (type === 'undefined') {
                    // It's a property
                    Object.defineProperty(comp.prototype, propertyName, {
                        get: function () {
                            return (this as any).wrappedInstance[propertyName];
                        },
                        set: function (value: any) {
                            (this as any).wrappedInstance[propertyName] = value;
                        }
                    });
                }
            }
        }

        return exposeWrappedMethods(comp, proto.__proto__);
    }

    return comp;
}

只需使用connect()打包exposeWrappedMethods即可使用它。它将添加您自己的类(和子类)中的所有方法和属性,但不会覆盖现有的方法(即来自React.Component基类的方法)。

export default exposeWrappedMethods(
    connect<any, any, Properties>(
        (state: ApplicationState) => state.counter,
        CounterState.actionCreators,
        null,
        { pure: false, withRef: true } // It requires use of "withRef: true"
    )(Counter)) as typeof Counter;

希望你(或其他人)认为它有用。

/卢卡斯

答案 2 :(得分:1)

可能有点迟,但使用refs的另一个(更好的)解决方案是仅控制组件的特定功能。

class A extends React.Component {
    constructor(props) {
        super(props);
    }

    componentDidMount() {
        this.ctrl_B.calledByParent()
    }

    render(){
        <B provideCtrl={ctrl => this.ctrl_B = ctrl} />
    }
}

class B extends React.Component {

    componentDidMount() {
        this.props.provideCtrl({
            calledByParent: () => this.calledByParent()
        });
    }
    componentWillUnmount() {
        this.props.provideCtrl(null);
    }

    calledByParent(){
        console.log("i'm called")
    }

    render(){
        <div> hello </div>
    }
}
export default  connect(mapStateToProps, mapDispatchToProps)(B)