react-native生命週期改造

weixin_33686714發表於2018-09-12

參考Native的宣告週期,你會發現RN缺少生命週期Hook--進入離開
你會發現除了第一次載入,我們沒有辦法再獲取它進入頁面的時機,離開就壓根沒有...

基於HOC和react-native-router-flux庫改造RN生命週期。
參考文章
custom-lifecycle-methods-in-react-native
React高階元件(HOC)模型理論與實踐
react-native-router-flux

廢話少說,直接上程式碼

生命週期Wrapper

import { AppState } from 'react-native';
import React, { Component } from 'react';

export function withWrappedComponent(WrappedComponent) {
  let componentInstance = null;
  let activeStatus = false;

  function componentWillAppear() {
    if(componentInstance && componentInstance.componentWillAppear && !activeStatus) {
      componentInstance.componentWillAppear()
    }
    activeStatus = true;
  }

  function componentWillDisappear() {
    if(componentInstance && componentInstance.componentWillDisappear && activeStatus) {
      componentInstance.componentWillDisappear();
    }
    
    activeStatus = false;
  }

  return class WrapperComponent extends Component {
    // 進入該元件時觸發,react-native-router-flux提供
    static onEnter() {
      componentWillAppear()
    }

    // 離開該元件時觸發,react-native-router-flux提供
    static onExit() {
      componentWillDisappear();
    }

    constructor(props) {
      super(props);
      activeStatus = true;

      // 監聽RN例項狀態改變
      // 1. 切換到Native的頁面
      // 2. APP前後臺切換(Home按鈕)
      AppState.addEventListener('change', this._handleAppStateChange);
    }

    _handleAppStateChange = (nextAppState) => {
      if (nextAppState === 'active') {
        componentWillAppear()
      } else {
        componentWillDisappear();
      }
    }

    componentDidMount() {
    }

    componentWillUnmount() {
      AppState.removeEventListener('change', this._handleAppStateChange);
      // componentInstance = null;
      activeStatus = false;
    }

    handleInstance(c) {
      Boolean(c) && (componentInstance = c);
    }

    render() {
      return <WrappedComponent ref={ c => this.handleInstance(c)} {...this.props}/>
    }
  }
}

使用方式

前置條件

  1. 主專案根目錄下執行npm i --save-dev babel-plugin-transform-decorators-legacy

  2. 建立.babelrc檔案,內容如下:

     {
       "presets": ["react-native"],
       "plugins": ["transform-decorators-legacy"]
     }
    

使用方法

import { withWrappedComponent } from 'xxx'

@withWrappedComponent
export class Home extends Component {
  componentWillAppear() {
    console.log("xxxxxxxxxxxx home componentWillAppear");
  }

  componentWillDisappear() {
    console.log("xxxxxxxxxxxx home componentWillDisappear");
  }
}

componentWillAppear在第二次進入該頁面/從後臺進入前臺觸發
componentWillDisappear在離開頁面時觸發/從前臺進入後臺觸發