reduxjs / redux-toolkit

The official, opinionated, batteries-included toolset for efficient Redux development
https://redux-toolkit.js.org
MIT License
10.59k stars 1.14k forks source link

RTK Query: refetchOnFocus is not working for me in a ReactNative app #3652

Open jr00n opened 12 months ago

jr00n commented 12 months ago

Hi, reading the docs at https://redux-toolkit.js.org/rtk-query/usage/cache-behavior#re-fetching-on-window-focus-with-refetchonfocus I expect my queries to be refetched when the app is gaining focus again when running in the background for a while...but nothing happens.

export const apiSlice = createApi({
  baseQuery: baseQueryWithReauth,
  endpoints: () => ({
  ...
  }),
  refetchOnFocus: true,
});

What do I miss?

Ahmedhamed77 commented 11 months ago

the same issue even if I added setupListeners(store.dispatch) it will not work too @phryneas does react-native requires an additional step to make refetchOnFocus and refetchOnReconnect work?

shivam9aug1996 commented 10 months ago

On web it works but on mobile its not working

markerikson commented 10 months ago

The current implementation is:

      if (typeof window !== 'undefined' && window.addEventListener) {
        // Handle focus events
        window.addEventListener(
          'visibilitychange',
          handleVisibilityChange,
          false
        )
        window.addEventListener('focus', handleFocus, false)

        // Handle connection events
        window.addEventListener('online', handleOnline, false)
        window.addEventListener('offline', handleOffline, false)
        initialized = true
      }

I genuinely have no idea if that even runs on React Native. Can anyone check and confirm if those events exist in RN?

phryneas commented 10 months ago

Yes, the default implementation of setupListeners is for web.

See https://github.com/reduxjs/redux-toolkit/pull/1931

We had a PR for documentation for this, but got stuck on the final implementation to put into the docs.

mikemonaco commented 7 months ago

It would be great if this was supported in React Native.

markerikson commented 7 months ago

@mikemonaco afraid we're not React Native users, and I have no idea how focus gets handled in RN. We'd be open to a PR that improves this, but I don't expect us to try to work on that ourselves.

phryneas commented 7 months ago

@mikemonaco The comment directly above your comment links to a step-by-step solution on how to get this working in React Native.

WhidRubeld commented 6 months ago

My working and tested code to set up listeners in React Native project

import NetInfo, {
  NetInfoState,
  NetInfoSubscription,
} from '@react-native-community/netinfo'
import { ThunkDispatch } from '@reduxjs/toolkit'
import { AppState, AppStateStatus, NativeEventSubscription } from 'react-native'

let initialized = false

let appStateSubscription: NativeEventSubscription | null = null
let appState = AppState.currentState

let netInfoUnsubscribe: NetInfoSubscription | null = null

export function listenHandler(
  dispatch: ThunkDispatch<any, any, any>,
  {
    onFocus,
    onFocusLost,
    onOffline,
    onOnline,
  }: {
    onFocus: () => void
    onFocusLost: () => void
    onOffline: () => void
    onOnline: () => void
  }
) {
  const handleFocus = () => dispatch(onFocus())
  const handleFocusLost = () => dispatch(onFocusLost())
  const handleOnline = () => dispatch(onOnline())
  const handleOffline = () => dispatch(onOffline())

  const _handleAppStateChange = (nextAppState: AppStateStatus) => {
    const foreground = !!(
      appState.match(/inactive|background/) && nextAppState === 'active'
    )

    if (foreground) handleFocus()
    else handleFocusLost()

    appState = nextAppState
  }

  const _handleNetInfoChange = (state: NetInfoState) => {
    const { isConnected } = state

    if (isConnected) handleOnline()
    else handleOffline()
  }

  if (!initialized) {
    appStateSubscription = AppState.addEventListener(
      'change',
      _handleAppStateChange
    )
    netInfoUnsubscribe = NetInfo.addEventListener(_handleNetInfoChange)
    initialized = true
  }

  const unsubscribe = () => {
    if (appStateSubscription) {
      appStateSubscription.remove()
      appStateSubscription = null
    }
    if (netInfoUnsubscribe) {
      netInfoUnsubscribe()
      netInfoUnsubscribe = null
    }
    initialized = false
  }

  return unsubscribe
}
anaselbahrawy commented 2 months ago

it's work with

setupListeners(store.dispatch)