Получить ссылку на компонент 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>
);
}
});
Ответы
Ответ 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". Не уверен, что это также может сыграть здесь роль.