優雅的在React元件中註冊事件
阿新 • • 發佈:2018-12-20
前言
在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>
);
}
}
總結
這種小技巧提高了開發效率,少寫了很多程式碼,可以在專案程式碼中嘗試。
來源:https://segmentfault.com/a/1190000017348517