Як отримати доступ до компонентних методів "ззовні" в 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.