Come accedere ai metodi dei componenti "dall'esterno" in ReactJS?


183

Perché non riesco ad accedere ai metodi del componente "dall'esterno" in ReactJS? Perché non è possibile e c'è un modo per risolverlo?

Considera il codice:

var Parent = React.createClass({
    render: function() {
        var child = <Child />;
        return (
            <div>
                {child.someMethod()} // expect "bar", got a "not a function" error.
            </div>
        );
    }
});

var Child = React.createClass({
    render: function() {
        return (
            <div>
                foo
            </div>
        );
    },
    someMethod: function() {
        return 'bar';
    }
});

React.renderComponent(<Parent />, document.body);

Forse hai bisogno Pubsub?
slideshowp2

Risposte:


203

React fornisce un'interfaccia per ciò che stai cercando di fare tramite l' refattributo . Assegna un componente a refe il suo currentattributo sarà il componente personalizzato:

class Parent extends React.Class {
    constructor(props) {
        this._child = React.createRef();
    }

    componentDidMount() {
        console.log(this._child.current.someMethod()); // Prints 'bar'
    }

    render() {
        return (
            <div>
                <Child ref={this._child} />
            </div>
        );
    }
}

Nota : funzionerà solo se il componente figlio viene dichiarato come classe, come da documentazione disponibile qui: https://facebook.github.io/react/docs/refs-and-the-dom.html#adding-a- ref-to-a-class-componente

Aggiornamento 2019-04-01: esempio modificato per utilizzare una classe e gli createRefultimi documenti React.

Aggiornamento 2016/09/19: esempio modificata per utilizzare callback ref per guida da parte dei refattributo String docs.


Quindi, l'unico modo per comunicare tra due componenti figlio sarebbe quello di avere refs e passare attraverso un metodo proxy sul genitore comune?
elQueFaltaba

15
React incoraggia i componenti basati sui dati. Consentire a un bambino di richiamare un callback che modifica i dati nel suo antenato e quando tali dati cambiano, l'altro figlio verrà nuovo propse verrà eseguito nuovamente il rendering in modo appropriato.
Ross Allen,

@RossAllen, ahah sì, avresti dovuto rimuovere anche il punto e virgola in quel caso.
HussienK,

@HussienK Preferisco usare un blocco se la funzione non deve avere un valore di ritorno, quindi l'intento è ovvio per il prossimo sviluppatore che legge il codice. Modificandolo in {(child) => this._child = child}si creerebbe una Funzione che ha sempre restituito true, ma quel valore non è usato dall'attributo di React ref.
Ross Allen,

39

Se vuoi chiamare funzioni su componenti esterni a React, puoi chiamarle sul valore di ritorno di renderComponent:

var Child = React.createClass({…});
var myChild = React.renderComponent(Child);
myChild.someMethod();

L'unico modo per ottenere un handle per un'istanza di React Component all'esterno di React è archiviare il valore di ritorno di React.renderComponent. Fonte .


1
in realtà funziona per reagire16. Il metodo di rendering ReactDOM restituisce un riferimento al componente (o restituisce null per i componenti senza stato).
Vlad Povalii,

37

In alternativa, se il metodo su Child è veramente statico (non un prodotto di oggetti di scena attuali, stato) è possibile definirlo staticse quindi accedervi come si farebbe con un metodo di classe statica. Per esempio:

var Child = React.createClass({
  statics: {
    someMethod: function() {
      return 'bar';
    }
  },
  // ...
});

console.log(Child.someMethod()) // bar

1
La fonte per questo è qui .
tirdadc,

7

A partire da React 16.3 React.createRefpuò essere utilizzato (usare ref.currentper accedere)

var ref = React.createRef()

var parent = <div><Child ref={ref} /> <button onClick={e=>console.log(ref.current)}</div>

React.renderComponent(parent, document.body)

4

Da React 0.12 l'API è leggermente cambiata . Il codice valido per inizializzare myChild sarebbe il seguente:

var Child = React.createClass({…});
var myChild = React.render(React.createElement(Child, {}), mountNode);
myChild.someMethod();

1

Si potrebbe anche fare in questo modo, non so se si tratta di un piano di buona: D

class Parent extends Component {
  handleClick() {
    if (this._getAlert !== null) {
      this._getAlert()
    }
  }

  render() {
    return (
      <div>
        <Child>
        {(getAlert, childScope) => (
          <span> {!this._getAlert ? this._getAlert = getAlert.bind(childScope) : null}</span>
        )}
        </Child>
        <button onClick={() => this.handleClick()}> Click me</button>
      </div>
      );
    }
  }

class Child extends Component {
  constructor() {
    super();
    this.state = { count: 0 }
  }

  getAlert() {
    alert(`Child function called state: ${this.state.count}`);
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return this.props.children(this.getAlert, this)
  }
}

1

Come menzionato in alcuni dei commenti, ReactDOM.rendernon restituisce più l'istanza del componente. È possibile passare un refcallback durante il rendering della radice del componente per ottenere l'istanza, in questo modo:

// React code (jsx)
function MyWidget(el, refCb) {
    ReactDOM.render(<MyComponent ref={refCb} />, el);
}
export default MyWidget;

e:

// vanilla javascript code
var global_widget_instance;

MyApp.MyWidget(document.getElementById('my_container'), function(widget) {
    global_widget_instance = widget;
});

global_widget_instance.myCoolMethod();

-1

Un altro modo così semplice:

funzione esterna:

function funx(functionEvents, params) {
  console.log("events of funx function: ", functionEvents);
  console.log("this of component: ", this);
  console.log("params: ", params);
  thisFunction.persist();
}

Legalo:

constructor(props) {
   super(props);
    this.state = {};
    this.funxBinded = funx.bind(this);
  }
}

Si prega di consultare il tutorial completo qui: Come usare "questo" di un componente React dall'esterno?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.