Подтвердить что ты не робот

Получить ссылку на компонент React в обработчике событий

Я могу привязать обработчик событий к компоненту 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>
        );
    }
});
4b9b3361

Ответ 1

Думаю, я понимаю вопрос, который задает вопрос vbarbarosh, или, по крайней мере, у меня был подобный, который привел меня к этому сообщению. Так что если это не ответит на исходный вопрос, надеюсь, это может помочь другим, кто приземляется здесь.

В моем случае у меня есть компонент React с n количеством детей для определения параметров конфигурации для действия пользовательского интерфейса. У каждого ребенка есть другое ref, определяющее, какой вариант конфигурации представляет вход, и я хочу, чтобы иметь возможность прямого доступа к ссылке, поэтому я могу затем вызвать методы, выставленные на моем дочернем компоненте. (Я мог бы предоставить данные 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()
}

Фокус в том, что при привязке порядок аргументов изменяется, а первый аргумент теперь передается связанным значением, а событие теперь является вторым аргументом. Надеюсь, что это поможет!

Ответ 2

handleMouseEnter в примере, который вы предложили (и уточнение, что onClick будет обработчиком, переданным Foobar) по умолчанию автоматически привязано по React к контексту экземпляра App в обоих случаях.

Учитывая это, this.refs.foo или this.refs['foo'] должны работать нормально в контексте, который вы описали, и будет правильным.

Более чистое решение, предполагающее, что нет никаких оснований держать обработчика в приложении, было бы сохранить обработчик полностью содержащимся в 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 />
        );
    }
});

Ответ 3

Вам придется распространять обработчик на корневой элемент вашего дочернего компонента, например:

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

Ответ 4

Если вы добавили обработчик программно, вы можете передать компонент в качестве параметра, просто связав обратный вызов обработчика с другой функцией в 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
}

Ответ 5

Хорошо глядя на ваш компонент приложения, вы можете попробовать следующее:

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 Components, который также немного изменяет поведение "this". Не уверен, что это также может сыграть здесь роль.