Як отримати доступ до компонентних методів "ззовні" в ReactJS?


183

Чому я не можу отримати доступ до компонентних методів "зовні" в ReactJS? Чому це неможливо і чи є спосіб вирішити це?

Розглянемо код:

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

Може, вам потрібно Pubsub?
слайд-

Відповіді:


203

React надає інтерфейс для того, що ви намагаєтеся зробити через refатрибут . Призначте компонент a ref, а його currentатрибут стане вашим спеціальним компонентом:

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

Примітка . Це буде працювати лише в тому випадку, якщо дочірній компонент оголошено як клас відповідно до документації, знайденої тут: https://facebook.github.io/react/docs/refs-and-the-dom.html#adding-a- компонент ref-to-a-class

Оновлення 2019-04-01: Змінено приклад для використання класу та createRefостанніх документів React.

Оновлення 2016-09-19: Змінено приклад використання рефа зворотного виклику кожного з керівництва по refатрибутам Струнних документів.


Отже, єдиним способом спілкування між двома дочірніми компонентами буде те, що обидва мають рефлекси та проходять метод проксі на загальному батьківському?
elQueFaltaba

15
React заохочує компоненти, керовані даними. Нехай одна дитина викликає зворотний виклик, який змінює дані про свого предка, а коли ці дані змінюються, інша дитина отримає нові propsта відобразиться належним чином.
Росс Аллен

@RossAllen, так, у цьому випадку вам також довелося б видалити крапку з комою.
HussienK

@HussienK Я вважаю за краще використовувати блок, якщо функція не повинна мати зворотного значення, тому наміри очевидні для наступного розробника, який читає код. Якщо змінити, щоб {(child) => this._child = child}створити функцію, яка завжди поверталася true, але це значення не використовується refатрибутом React .
Росс Аллен

39

Якщо ви хочете викликати функції на компонентах, що знаходяться за межами React, ви можете зателефонувати їм за зворотним значенням renderComponent:

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

Єдиний спосіб отримати ручку до екземпляра React Component за межами React - це збереження зворотного значення React.renderComponent. Джерело .


1
насправді це працює на реакцію16. Метод візуалізації ReactDOM повертає посилання на компонент (або повертає нуль для компонентів без стану).
Влад Повалій

37

Крім того, якщо метод Child є справді статичним (не продуктом поточних реквізитів, штату), ви можете визначити його staticsта отримати доступ до нього, як і метод статичного класу. Наприклад:

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

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

1
Джерело для цього є тут .
tirdadc

7

Станом на React 16.3 React.createRefможна використовувати (використовувати ref.currentдля доступу)

var ref = React.createRef()

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

React.renderComponent(parent, document.body)


1

Ви могли б також зробити це так, не впевнений , якщо це план добре: 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

Як було сказано в деяких коментарях, ReactDOM.renderбільше не повертає екземпляр компонента. Ви можете передати refзворотний виклик, коли надаватимете корінь компонента, щоб отримати екземпляр, наприклад:

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

і:

// vanilla javascript code
var global_widget_instance;

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

global_widget_instance.myCoolMethod();

-1

Ще один простий спосіб:

функція зовні:

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

Прив’яжіть:

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

Будь ласка, дивіться повний підручник тут: Як використовувати "це" Реактивний компонент ззовні?

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.