201
votes

Why can’t I access the component methods from “outside” in ReactJS? Why is it not possible and is there any way to solve it?

Consider the code:

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);
8
Maybe you need Pubsub ?slideshowp2

8 Answers

215
votes

React provides an interface for what you are trying to do via the ref attribute. Assign a component a ref, and its current attribute will be your custom component:

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

Note: This will only work if the child component is declared as a class, as per documentation found here: https://facebook.github.io/react/docs/refs-and-the-dom.html#adding-a-ref-to-a-class-component

Update 2019-04-01: Changed example to use a class and createRef per latest React docs.

Update 2016-09-19: Changed example to use ref callback per guidance from the ref String attribute docs.

39
votes

If you want to call functions on components from outside React, you can call them on the return value of renderComponent:

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

The only way to get a handle to a React Component instance outside of React is by storing the return value of React.renderComponent. Source.

37
votes

Alternatively, if the method on Child is truly static (not a product of current props, state) you can define it on statics and then access it as you would a static class method. For example:

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

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

As of React 16.3 React.createRef can be used, (use ref.current to access)

var ref = React.createRef()

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

React.renderComponent(parent, document.body)
4
votes

Since React 0.12 the API is slightly changed. The valid code to initialize myChild would be the following:

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

You could also do it like this, not sure if it's a good 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
votes

As mentioned in some of the comments, ReactDOM.render no longer returns the component instance. You can pass a ref callback in when rendering the root of the component to get the instance, like so:

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

and:

// vanilla javascript code
var global_widget_instance;

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

global_widget_instance.myCoolMethod();
-1
votes

Another way so easy:

function outside:

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

Bind it:

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

Please see complete tutorial here: How to use "this" of a React Component from outside?