前言
在React的開發中,我們經常需要在 window 上註冊一些事件, 比如按下 Esc 關閉彈窗, 按上下鍵選中列表內容等等。比較常見的操作是在元件 mount 的時候去 window 上監聽一個事件, 在元件 unmount 的時候停止監聽事件。下面給大家介紹幾個騷操作。
WindowEventHandler
我們建立一個 WindowEventHandler 元件, 內容如下
import PropTypes from `prop-types`;
import { Component, PureComponent } from `react`;
export default class WindowEventHandler extends (PureComponent || Component) {
static propTypes = {
eventName: PropTypes.string.isRequired,
callback: PropTypes.func.isRequired,
useCapture: PropTypes.bool,
};
static defaultProps = {
useCapture: false,
};
componentDidMount() {
const { eventName, callback, useCapture } = this.props;
window.addEventListener(eventName, callback, useCapture);
}
componentWillUnmount() {
const { eventName, callback, useCapture } = this.props;
window.removeEventListener(eventName, callback, useCapture);
}
render() {
return null;
}
}
現在比如我們想在元件A中監聽 window 的 resize 事件,我們在 A 元件中可以這麼寫
export default class A extends (PureComponent || Component) {
handleResize = () => {
// dosomething...
}
render() {
return (
<div>
我是元件A
<WindowEventHandler eventName="resize" callback={this.handleResize} />
</div>
);
}
}
這樣我們在多個元件中就不需要每次都要寫 mount 和 unmount 的鉤子函式了,省了很多事情。
使用裝飾器
我們可以給元件寫一個統一的裝飾器,和之前一樣傳入事件名和方法名就可以監聽,等到元件解除安裝的時候就停止監聽,程式碼如下
export default function windowEventDecorator(eventName, fn) {
return function decorator(Component) {
return (...args) => {
const inst = new Component(...args);
const instComponentDidMount = inst.componentDidMount ? inst.componentDidMount.bind(inst) : undefined;
const instComponentWillUnmount = inst.instComponentWillUnmount ? inst.componentWillUnmount.bind(inst) : undefined;
const callback = (e) => {
typeof inst[fn] === `function` && inst[fn]();
};
inst.componentDidMount = () => {
instComponentDidMount && instComponentDidMount();
document.body.addEventListener(eventName, callback, true);
};
inst.componentWillUnmount = () => {
instComponentWillUnmount && instComponentWillUnmount();
document.body.removeEventListener(eventName, callback, true);
};
return inst;
};
};
}
類似這樣的裝飾器,同理我們想在 A 中監聽 window 的 resize 事件,可以這麼寫
@windowEventDecorator(`resize`, `handleResize`);
export default class A extends (PureComponent || Component) {
handleResize = () => {
// dosomething...
}
render() {
return (
<div>
我是元件A
</div>
);
}
}
總結
這種小技巧提高了開發效率,少寫了很多程式碼,可以在專案程式碼中嘗試。