react-native中的应用程序状态不会删除侦听器

lg40wkob  于 2023-01-14  发布在  React
关注(0)|答案(8)|浏览(258)

我用以下方法添加了侦听器(尝试同时放入构造函数和componentDidMount):应用状态.addEventListener('更改',此._handleAppStateChange);
并且在componentWillUnmount方法中以以下方式删除了侦听器:
应用状态.removeEventListener('更改',此._handleAppStateChange);
在回调函数中:

_handleAppStateChange = (nextAppState) => {
    setTimeout(() => {
      alert('App state: ' + this.state.appState);
      alert('Next App state: ' + nextAppState);
    }, 0);
  }

它发出了几次警报。它没有删除配置的侦听器一次。请让我知道是否有人知道它?

7uhlpewt

7uhlpewt1#

    • 根据最新文档(2021年9月v0.65+),removeEventListener已弃用**

文档现在建议对从AppState.addEventListener返回的订阅对象(EmitterSubscription)使用remove函数。
示例用法:

const subscription = AppState.addEventListener('change', (appState) => {
  if (appState !== 'active') {
    return;
  }

  // Run custom logic

  subscription.remove();
});
oewdyzsn

oewdyzsn2#

你应该像现在这样使用API

useEffect(() => {
 const myListener = AppState.addEventListener('change', this.someHandler)
 return () => {
   myListener.remove()
 }
}, [])
5cnsuln7

5cnsuln73#

最近几天我也遇到了同样的问题,我最终通过将应用状态管理迁移到App.js组件并创建了一个服务管理器来解决这个问题。
下面是我的App.js的大致情况:

import {AppState } from "react-native";
import {AppStateService} from "YOUR_PATH_TO_THE_NEXT_FILE";

export default function App() {

    // Listen to app state
    AppStateService.init();
    useEffect(() => {
        AppState.addEventListener('change', AppStateService.getInstance().handleAppStateChange);
        return (() => {
            AppState.removeEventListener('change', AppStateService.getInstance().handleAppStateChange);
        })
    }, []);

    return (/*Rendering stuff (navigation, error boundary, ...*/);
}

AppStateService.js

/**
 * Class to allow us to refer to the app state service
 */

export class AppStateService {

    static instance;

    static STATE_ACTIVE         = 'active';
    static STATE_INACTIVE       = 'inactive';
    static STATE_BACKGROUND     = 'background';
    static STATE_NOT_LAUNCHED   = 'not_launched';

    previousState   = AppStateService.STATE_NOT_LAUNCHED;
    currentState    = AppStateService.STATE_ACTIVE;

    handlers = {};

    appLaunchId = 0;

    /**
     * @returns {AppStateService}
     */
    static getInstance() {
        if(!this.instance){
            this.instance = new AppStateService();
        }

        return this.instance;
    }

    static init = () => {
        // This func need to be call in the App.js, it's just here to create the instance
        const instance = AppStateService.getInstance();

        instance.appLaunchId = new Date().getTime() / 1000;
    }

    handleAppStateChange = (nextState) => {
        if(nextState !== this.currentState) {
            this.previousState = this.currentState;
            this.currentState = nextState;

            for (const [key, handler] of Object.entries(this.handlers)) {
                handler(nextState);
            }
        }
    }

    getCurrentState = () => {
        return this.currentState;
    }

    getPreviousState = () => {
        return this.previousState;
    }

    addStateHandler = (key, handler) => {
        this.handlers[key] = handler;
    }

    hasStateHandler = (key) => {
        if( this.handlers[key] ){
            return true;
        }

        return false;
    }

    removeStateHandler = (key) => {
        delete this.handlers[key];
    }
}

下面是如何从应用组件中的任意位置调用它:

export default class RandomComponent extends React.Component {
    
    componentDidMount() {
        // Check app going background or not
        this.handleAppStateChange = this.handleAppStateChange.bind(this);
        AppStateService.getInstance().addStateHandler('myListenerCustomKey', this.handleAppStateChange);
    }

    componentWillUnmount() {
        // Remove app state change listener
        AppStateService.getInstance().removeStateHandler('myListenerCustomKey');
    }

    handleAppStateChange = (nextAppState) => {
        console.log("I'm going to be -" + nextAppState + "- while I was -" + AppStateService.getInstance().getPreviousState() + "-");
    }
}

这样,您就可以在应用中的任何位置监听应用前台/非活动/后台状态,并正确订阅/取消订阅这些事件。

6ie5vjzr

6ie5vjzr4#

从代码的外观来看,我假设您使用的是类组件,我解决这个问题的方法是创建一个指针函数,指向this作用域内的实际函数,而不使用.bind(this)
例如

// Actual Function    
handleAppStateChange(state) {
  // Work your magic!
}

// Pointer
handleAppStateChangeCall = (state) => this.handleAppStateChange(state);

// Setup listener event
setupAppStateListener() {
  AppState.addEventListener("change", this.handleAppStateChangeCall);
}

// Clear listener event
clearAppStateListener() {
  AppState.addEventListener("change", this.handleAppStateChangeCall);
}

// Mounted Hook
componentDidMount() { 
  setupAppStateListener();
}

// Unmount Hook
componentWillUnmount() {
  clearAppStateListener()
}
vulvrdjw

vulvrdjw5#

必须从ComponentWillUnmount函数中删除侦听器

componentWillUnmount() {
    AppState.removeEventListener('change', this._handleAppStateChange);
  }
gmxoilav

gmxoilav6#

设置状态是一个异步进程。因此在componentWillUnmount中,不要将其用作组件卸载,并且对于该场景,setState仍在进程中,从而导致警报。

jslywgbw

jslywgbw7#

可能是由于您正在收听的功能发生变化而导致的

this.props.navigation.addListener(
  'didFocus',
  () => {
    AppState.addEventListener('change', this.handleAppStateChange)
  }
)
this.props.navigation.addListener(
  'willBlur',
  () => {
    AppState.removeEventListener('change', this.handleAppStateChange)
  }
)

它工作正常

this.props.navigation.addListener(
  'didFocus',
  () => {
    AppState.addEventListener('change', this.handleAppStateChange.bind(this))
  }
)
this.props.navigation.addListener(
  'willBlur',
  () => {
    AppState.removeEventListener('change', this.handleAppStateChange.bind(this))
  }
)

它不工作,所以也许你需要这样

this.handleAppStateChange = this.handleAppStateChange.bind(this)

在构造函数中

eni9jsuy

eni9jsuy8#

我们可以修改代码如下:
使用效果(()=〉{常量状态监听器=应用状态.添加事件监听器('change ',handleAppStateChange);

return () => {
  stateListener.remove();
};

}、[]);
常量句柄应用状态更改=(下一个应用状态)=〉{if(应用状态.当前.匹配(/inactive|background/)&& nextAppState ==='active'){console. log('应用程序已进入前台!');设置连接状态(真);} else {console. log('App已进入后台或不活动!');设置连接状态(假);}

appState.current = nextAppState;
setAppStateVisible(appState.current);
console.log('AppState is ', appState.current);

};

相关问题