在事件处理程序中获取对React组件的引用

时间:2015-01-20 15:51:17

标签: reactjs

我可以将我的事件处理程序附加到React组件。有没有办法在事件处理程序中获取对此组件的引用?

var Foobar = React.createClass({
    action: function () {
        // ...
    },
    render: function () {
        var child = React.Children.only(this.props.children),
            props = _.omit(this.props, 'children');
        return React.addons.cloneWithProps(child, props);
    }
});

var App = React.createClass({
    handleMouseEnter: function (event) {
        // How to get reference to Foobar without using this.refs['foo']?
        // I need to call *action* on it.
    },
    render: function () {
        return (
            <div>
                <Foobar ref="foo" onMouseEnter={this.handleMouseEnter}>
                    ...
                </Foobar>
            </div>
        );
    }
});

5 个答案:

答案 0 :(得分:38)

我想我理解vbarbarosh正在问的问题,或者至少我有一个类似的问题引导我发表这篇文章。因此,如果这不能回答原始问题,希望它可以帮助那些降落在这里的人。

在我的情况下,我有一个带有 n 子项数的React组件,用于定义UI操作的配置选项。每个孩子都有一个不同的引用,用于标识输入所代表的配置选项,并且我希望能够直接访问引用,以便我可以调用在我的子组件上公开的方法。 (我可以公开数据attrs并使用jQuery来提取,但这似乎有很多额外的箍和性能问题)

我的第一次尝试是:

...
<Config ref="showDetails" onChange={this.handleChange} />
<Config ref="showAvatar" onChange={this.handleChange} />
...

理想情况下,我想将所有更改事件绑定到单个处理程序,然后从调度事件的目标中提取ref。不幸的是,已发送的SyntheticEvent 提供了获取目标参考号的方法,因此我无法直接拨打this.ref[name].methodIWantToCall()

我找到的是React文档中的一篇文章,它引导我找到解决方案:

https://facebook.github.io/react/tips/communicate-between-components.html

我们可以做的是利用JavaScript绑定并传入其他参数。

...
<Config ref="showDetails" onChange={this.handleChange.bind(this, 'showDetails')} />
...

现在在我的处理程序中,我获得了附加数据并可以访问我的参考:

handleChange: function(refName, event) {
  this.refs[refName].myMethodIWantToCall()
}

诀窍是绑定时,参数顺序会改变,第一个参数现在是传入的绑定值,事件现在是第二个参数。希望有所帮助!

答案 1 :(得分:4)

您提供的示例中的

handleMouseEnter(并且澄清onClick将是传递给Foobar的处理程序)默认情况下由React自动绑定到App实例的上下文。

考虑到这一点,this.refs.foothis.refs['foo']应该在您描述的上下文中正常工作,并且是正确的方法。

一个更干净的解决方案,假设没有令人信服的理由将处理程序保留在App中,那就是将处理程序完全包含在Foobar中,如下所示:

var Foobar = React.createClass({
    action: function () {
        // ...
    },
    render: function () {
        var child = React.Children.only(this.props.children),
            props = _.omit(this.props, 'children');
        return (
            <div onClick={this.action} onMouseEnter={this.action}>
                React.addons.cloneWithProps(child, props);
            </div>
        );
    }
});

var App = React.createClass({
    render: function () {
        return (
            <Foobar />
        );
    }
});

答案 2 :(得分:4)

您必须将处理程序传播到子组件的根元素,如下所示:

var Foobar = React.createClass({
    action: function (e) {
        this.props.onClick(this);
    },
    render: function () {
        return <div onClick={this.action}>{this.props.children}</div>;
    }
});

var App = React.createClass({
    handleMouseEnter: function (foobar) {
       console.log(foobar);
    },
    render: function () {
        return (
            <Foobar ref="foo" onClick={this.handleMouseEnter} />
        );
    }
});

答案 3 :(得分:0)

如果以编程方式添加处理程序,只需将处理程序回调与addEventListener处的另一个函数包装在一起,就可以将组件作为参数传递。

我有这个例子使用滚动事件:

componentDidMount() {
    document.getElementById('theElementId').addEventListener('scroll', (e) => {
        this.handleScroll(e, this);
    });
}

handleScroll(event, _self) {
    // Now you can access to the element using the param _self
}

render() {
    return (
        <div id="theElementId"></div>
    )
}

另一种选择是使用bind方法,它将改变this

的值
componentDidMount() {
    document.getElementById('theElementId').addEventListener('scroll', this.handleScroll.bind(this));
}

handleScroll(event) {
    // Now you can access to the element using the param this
}

答案 4 :(得分:0)

好好看看你的App Component,你可以试试这个:

var App = React.createClass({
handleMouseEnter: function (event) {
    // reference it by using: this.refs[event._targetInst._currentElement.ref]
    // same result as calling: this.refs.foo
    console.log(this.refs[event._targetInst._currentElement.ref])
},
render: function () {
    return (
        <div>
            <Foobar ref="foo" onMouseEnter={this.handleMouseEnter}>
                ...
            </Foobar>
        </div>
        );
    }
});

希望这会有所帮助。 :) 另外,我使用ES6编写/声明React组件的方式,这也改变了&#34;这个&#34;的行为。一点点。不确定这是否也可能在这里发挥作用。