为什么我不能在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);

当前回答

React通过ref属性提供了一个接口,用于您尝试执行的操作。为一个组件分配一个ref,它的当前属性将是你的自定义组件:

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

更新2019-04-01:更改示例,每个最新的React文档使用一个类和createRef。

更新2016-09-19:修改示例,从ref String属性文档中使用ref回调。

其他回答

正如在一些评论中提到的,ReactDOM。渲染不再返回组件实例。你可以在呈现组件的根时传入一个ref回调来获取实例,如下所示:

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

自React 0.12以来,API略有变化。初始化myChild的有效代码如下:

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

React通过ref属性提供了一个接口,用于您尝试执行的操作。为一个组件分配一个ref,它的当前属性将是你的自定义组件:

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

更新2019-04-01:更改示例,每个最新的React文档使用一个类和createRef。

更新2016-09-19:修改示例,从ref String属性文档中使用ref回调。

你也可以这样做,不确定这是不是一个好计划: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)
  }
}

或者,如果Child上的方法是真正静态的(不是当前props、state的产物),你可以在静态上定义它,然后像访问静态类方法一样访问它。例如:

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

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