Como acessar métodos de componentes de "fora" no ReactJS?

183

Por que não consigo acessar os métodos do componente de "fora" no ReactJS? Por que não é possível e existe alguma maneira de resolvê-lo?

Considere o código:

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);
user1518183
fonte
Talvez você precise Pubsub?
Slideshowp2

Respostas:

203

Reagir fornece uma interface para o que você está tentando fazer através do refatributo . Atribua um componente a refe seu currentatributo será seu componente personalizado:

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 : Isso funcionará apenas se o componente filho for declarado como uma classe, conforme a documentação encontrada aqui: https://facebook.github.io/react/docs/refs-and-the-dom.html#adding-a- ref-para-um-classe-componente

Atualização 2019-04-01: Exemplo alterado para usar uma classe e pelos createRefdocumentos mais recentes do React.

Atualização 19/09/2016: Exemplo alterado para usar o retorno de chamada ref por orientação nosref documentos do atributo String .

Ross Allen
fonte
Portanto, a única maneira de se comunicar entre dois componentes filhos seria com referências e passando por um método proxy no pai comum?
ElQueFaltaba
15
O React incentiva os componentes controlados por dados. Permita que um filho chame um retorno de chamada que altere os dados em seu ancestral e, quando esses dados forem alterados, o outro filho será novo propse será renderizado adequadamente.
Ross Allen
@ RossAllen, haha ​​sim, você teria que remover o ponto-e-vírgula também nesse caso.
HussienK
@HussienK Prefiro usar um bloco se a função não tiver um valor de retorno, portanto a intenção é óbvia para o próximo desenvolvedor que ler o código. Alterar isso para {(child) => this._child = child}criaria uma função que sempre retornava true, mas esse valor não é usado pelo refatributo do React .
Ross Allen
39

Se você quiser chamar funções em componentes de fora do React, poderá chamá-las no valor de retorno de renderComponent:

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

A única maneira de obter um identificador para uma instância do React Component fora do React é armazenando o valor de retorno React.renderComponent. Fonte .

Sjoerd
fonte
1
na verdade, funciona para react16. O método de renderização ReactDOM retorna uma referência ao componente (ou retorna nulo para componentes sem estado).
precisa saber é o seguinte
37

Como alternativa, se o método em Child for realmente estático (não um produto dos adereços atuais, estado), você poderá defini-lo staticse acessá-lo como faria com um método de classe estática. Por exemplo:

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

console.log(Child.someMethod()) // bar
Paul O'Shannessy
fonte
1
A fonte para isso está aqui .
2141515
7

A partir do React 16.3 React.createRefpode ser usado (use ref.currentpara acessar)

var ref = React.createRef()

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

React.renderComponent(parent, document.body)
Jay
fonte
4

Desde o React 0.12, a API foi ligeiramente alterada . O código válido para inicializar myChild seria o seguinte:

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

Você também pode fazer assim, sem ter certeza se é um bom plano: 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)
  }
}
swennemen
fonte
1

Conforme mencionado em alguns dos comentários, ReactDOM.rendernão retorna mais a instância do componente. Você pode passar um refretorno de chamada ao renderizar a raiz do componente para obter a instância, assim:

// 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();
mgalgs
fonte
-1

Outra maneira tão fácil:

função fora:

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

Vincule-o:

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

Por favor, veja o tutorial completo aqui: Como usar "isto" de um Componente React de fora?

Hou Soune
fonte