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

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.


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 .


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

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)

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

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

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

-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?

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.