2017-02-03 5 views
2

Anfangs funktionierte alles gut, ich habe eine Komponente so etwas wie. dieseZugriff auf untergeordnete Funktion über ref nicht möglich?

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"/> 
    } 
    } 

In anderen Datei

 class B extends React.Component { 

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

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

bis hier war es funktioniert gut, aber wenn ich so etwas tun in class Bexport default connect(mapStateToProps, mapDispatchToProps)(B)

Es funktioniert nicht. Ich habe von react-redux connect

+2

Sinnvoll, weil 'connect' eine andere Komponente um das Parent umschließt. Also, was ist die Frage? –

Antwort

5

connect() importiert akzeptiert option als der vierte Parameter. In diesem Optionsparameter können Sie das Flag withRef auf true setzen. Danach können Sie auf die Funktionen zugreifen, indem Refs getWrappedInstance() wie

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

    componentDidMount() { 
     this.refs.b.getWrappedInstance().calledByParent() 
    } 

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

class B extends React.Component { 

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

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

mit ein wenig zu spät sein könnte, aber eine andere (bessere) Lösung als Refs Verwendung ist nur die Steuerung auf bestimmte Funktionen der Komponente zu geben.

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) 
2

Ich hatte ähnliches Problem, aber ich wollte nicht meine APIs abhängig von getWrappedInstance() Anrufe tätigen. Tatsächlich können einige Komponenten in Ihrer Klassenhierarchie connect() verwenden und auf den Speicher zugreifen, und einige andere sind nur zustandslose Komponenten, die diese zusätzliche Redux-Schicht nicht benötigen.

Ich habe gerade eine kleine (vielleicht ein bisschen hackish) Methode geschrieben. Bitte beachten Sie, dass es noch nicht vollständig getestet wurde, also erwarten Sie, dass Sie einige Anpassungen vornehmen müssen, damit es in Ihrem eigenen Szenario funktioniert.

Typoskript (sollte reine JavaScript-Syntax leicht zu konvertieren sein):

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; 
 
}

Verwenden Sie es, indem Sie einfach mit exposeWrappedMethods Ihre connect() Anruf wickeln. Es fügt alle Methoden und Eigenschaften aus Ihrer eigenen Klasse (und Unterklassen) hinzu, überschreibt jedoch nicht bereits existierende Methoden (d. H. Methoden aus der Basisklasse 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;

Hoffnung, die Sie (oder jemand anderes) es nützlich finden.

/Lukasz

Verwandte Themen