220

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);
1
  • Maybe you need Pubsub ? Commented Nov 4, 2016 at 7:18

8 Answers 8

223

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.

Sign up to request clarification or add additional context in comments.

4 Comments

So, the only way to communicate between two child components would be with both having refs and going through a proxy method on the common parent?
React encourages data-driven components. Let one child call a callback that changes data in its ancestor, and when that data changes the other child will get new props and re-render appropriately.
@RossAllen, haha yes, you would have had to remove the semicolon too in that case.
@HussienK I prefer to use a block if the function should have no return value so intent is obvious to the next developer who reads the code. Changing that to {(child) => this._child = child} would create a Function that always returned true, but that value is not used by React's ref attribute.
40

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.

1 Comment

actually it works for react16. ReactDOM render method returns a reference to the component (or returns null for stateless components).
38

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

1 Comment

Source for this is here.
10

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)

Comments

4

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

Comments

2

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

Comments

2

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

Comments

-1

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?

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.