Jak uzyskać dostęp do metod komponentów z „zewnątrz” w ReactJS?

183

Dlaczego nie mogę uzyskać dostępu do metod komponentów „z zewnątrz” w ReactJS? Dlaczego nie jest to możliwe i czy jest jakiś sposób na jego rozwiązanie?

Rozważ kod:

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);
użytkownik1518183
źródło
Może trzeba Pubsub?
slideshowp2

Odpowiedzi:

203

React zapewnia interfejs do tego, co próbujesz zrobić za pomocą refatrybutu . Przypisz składnik a ref, a jego currentatrybut będzie składnikiem niestandardowym:

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

Uwaga : Działa to tylko wtedy, gdy komponent potomny zostanie zadeklarowany jako klasa, zgodnie z dokumentacją znajdującą się tutaj: https://facebook.github.io/react/docs/refs-and-the-dom.html#adding-a- ref-to-a-class-component

Aktualizacja 2019-04-01: Zmieniono przykład użycia klasy i createRefnajnowszych dokumentów React.

Aktualizacja 19.09.2016: Zmieniono przykład użyć ref zwrotnego za wytycznymi z tych refatrybutów Smyczkowych docs.

Ross Allen
źródło
Czy zatem jedynym sposobem komunikacji między dwoma komponentami potomnymi byłoby posiadanie referencji i przejście przez metodę proxy na wspólnym rodzicu?
elQueFaltaba
15
React zachęca do tworzenia komponentów opartych na danych. Pozwól jednemu dziecku wywołać wywołanie zwrotne, które zmienia dane w jego przodku, a gdy te dane się zmienią, drugie dziecko otrzyma nowe propsi odpowiednio zrenderuje.
Ross Allen
@ RossAllen, haha ​​tak, w takim przypadku musiałbyś również usunąć średnik.
HussienK
@HussienK Wolę użyć bloku, jeśli funkcja nie powinna mieć wartości zwracanej, więc zamiar jest oczywisty dla następnego programisty, który czyta kod. Zmiana tej wartości {(child) => this._child = child}spowoduje utworzenie funkcji, która zawsze zwraca true, ale ta wartość nie jest używana przez refatrybut React .
Ross Allen
39

Jeśli chcesz wywoływać funkcje na komponentach spoza React, możesz je wywołać na wartości zwracanej przez renderComponent:

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

Jedynym sposobem na uzyskanie dojścia do instancji React Component poza React jest przechowywanie wartości zwracanej React.renderComponent. Źródło .

Sjoerd
źródło
1
właściwie to działa na reakcję16. Metoda renderowania ReactDOM zwraca odwołanie do komponentu (lub zwraca null dla komponentów bezstanowych).
Vlad Povalii,
37

Alternatywnie, jeśli metoda na Child jest naprawdę statyczna (nie jest produktem bieżących rekwizytów, stan), możesz ją zdefiniować, staticsa następnie uzyskać do niej dostęp, tak jak metoda klasy statycznej. Na przykład:

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

console.log(Child.someMethod()) // bar
Paul O'Shannessy
źródło
1
Źródło tego znajduje się tutaj .
tirdadc
7

Od React 16.3 React.createRefmożna używać, (użyj, ref.currentaby uzyskać dostęp)

var ref = React.createRef()

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

React.renderComponent(parent, document.body)
Sójka
źródło
4

Od React 0.12 interfejs API został nieznacznie zmieniony . Prawidłowy kod do zainicjowania myChild byłby następujący:

var Child = React.createClass({…});
var myChild = React.render(React.createElement(Child, {}), mountNode);
myChild.someMethod();
Jewgienij Safronow
źródło
1

Możesz to zrobić w ten sposób, nie jestem pewien, czy to dobry plan: 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
źródło
1

Jak wspomniano w niektórych komentarzach, ReactDOM.rendernie zwraca już instancji komponentu. Możesz przekazać refwywołanie zwrotne podczas renderowania katalogu głównego komponentu, aby uzyskać instancję, na przykład:

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

i:

// vanilla javascript code
var global_widget_instance;

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

global_widget_instance.myCoolMethod();
mgalgs
źródło
-1

Kolejny sposób tak łatwy:

funkcja na zewnątrz:

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

Wiąż to:

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

Zobacz pełny samouczek tutaj: Jak korzystać z „tego” komponentu React z zewnątrz?

Hou Soune
źródło