我的应用程序中有一些组件可以处理键盘上的某些用户输入。为此,我创建了以下功能:
export default function withKeydownEventHandler (handler) {
id = id + 1
return lifecycle({
componentWillMount () {
$(window).on(`keydown.${id}`, evt => handler(evt))
},
componentWillUnmount () {
$(window).off(`keydown.${id}`)
}
})
}
这很好,但是同时为不同的组件触发了处理程序。因此,如果我的处理程序在每个组件中执行不同的操作,则每当我单击一个按钮时,它将同时从两个组件中触发。此外,一旦卸下一个组件,HoC将不再起作用。
例如,说我有以下两个容器:
export default compose(
withKeydownEventHandler((evt, props) => {
console.warn('hi from Component 1')
}),
withProps(() => {
// stuff
})
)(Component1)
export default compose(
withKeydownEventHandler((evt, props) => {
console.warn('hi from Component 2')
}),
withProps(() => {
// stuff
})
)(Component2)
如果我在整个应用程序中单击任何按钮,则会得到以下输出:
嗨,组件1
组件2的嗨
另一方面,一旦其中一个组件被卸载,我将不再有任何事件。
我在做什么错?如何通过HoC获取一个keydown事件处理程序,该事件处理程序可以在我的应用程序中重复使用?
答案 0 :(得分:3)
首先,请您注意您的id
被设置为全局变量。您确定要使用全局变量吗?
第二,您使用$(window).on('keydown.${id}', evt => handler(evt))
将keydown事件绑定到窗口,该事件解释了您的不良行为。您需要将其与要让处理程序执行操作的特定组件绑定一次。
最后,为什么不创建HOC类并有条件地添加事件侦听器?类似于以下内容:
// src/Hoc.jsx
export default function(WrapperComponent) {
return class extends Component {
componentWillMount () {
const { onKeyDownHandler } = this.props;
if (isKeyDownEventNeeded) {
this.comp.addEventListener("keydown", onKeyDownHandler);
}
}
componentWillUnmount () {
const { onKeyDownHandler } = this.props;
if (isKeyDownEventNeeded) {
this.comp.removeEventListener("keydown", onKeyDownHandler);
}
}
render() {
const { onKeyDownHandler } = this.props;
if (onKeyDownHandler) {
// a "ref" callback which assigns the mounted
// Element to a prop "comp" whicu can be used later to add the DOM listener to.
return <WrapperComponent ref={elem => this.comp = elem} {...this.props} />
}
return <WrapperComponent {...this.props} />
}
}
export default HighOrderComponent;
然后
// somewhere-else.js
import highOrderComponent from 'src/Hoc'
highOrderComponent(<Component1 onKeyDownHandler={() => console.log('hey, Component 1'} />
highOrderComponent(<Component2 onKeyDownHandler={() => console.log('hey, Component 2'} />
有关如何结帐this answer
的更多信息