優雅的在React組件中註冊事件

前言

在React的開發中,咱們常常須要在 window 上註冊一些事件, 好比按下 Esc 關閉彈窗, 按上下鍵選中列表內容等等。比較常見的操做是在組件 mount 的時候去 window 上監聽一個事件, 在組件 unmount 的時候中止監聽事件。下面給你們介紹幾個騷操做。react

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 組件中能夠這麼寫ui

export default class A extends (PureComponent || Component) {
  
  handleResize = () => {
   // dosomething...
  }
  render() {
    return (
        <div>
            我是組件A 
            <WindowEventHandler eventName="resize" callback={this.handleResize} />
        </div>
    );
  }
}

這樣咱們在多個組件中就不須要每次都要寫 mount 和 unmount 的鉤子函數了,省了不少事情。this

使用裝飾器

咱們能夠給組件寫一個統一的裝飾器,和以前同樣傳入事件名和方法名就能夠監聽,等到組件卸載的時候就中止監聽,代碼以下code

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 事件,能夠這麼寫component

@windowEventDecorator('resize', 'handleResize');
export default class A extends (PureComponent || Component) {
  
  handleResize = () => {
   // dosomething...
  }
  render() {
    return (
        <div>
            我是組件A 
        </div>
    );
  }
}

總結

這種小技巧提升了開發效率,少寫了不少代碼,能夠在項目代碼中嘗試。事件

相關文章
相關標籤/搜索