Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

docs(react): update the react-native.md section #8506

Merged
merged 4 commits into from
Jan 8, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 9 additions & 88 deletions docs/framework/react/react-native.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,108 +92,29 @@ export function useRefreshOnFocus<T>(refetch: () => Promise<T>) {

In the above code, `refetch` is skipped the first time because `useFocusEffect` calls our callback on mount in addition to screen focus.

## Disable re-renders on out of focus Screens

In some situations, including performance concerns, you may want to stop re-renders when a React Native screen gets out of focus. To achieve this we can use `useFocusEffect` from `@react-navigation/native` together with the `notifyOnChangeProps` query option.

This custom hook provides a `notifyOnChangeProps` option that will return an empty array whenever a screen goes out of focus - effectively stopping any re-renders on that scenario. Whenever the screens gets in focus again, the behavior goes back to normal.

```tsx
import React from 'react'
import { NotifyOnChangeProps } from '@tanstack/query-core'
import { useFocusEffect } from '@react-navigation/native'

export function useFocusNotifyOnChangeProps(
notifyOnChangeProps?: NotifyOnChangeProps,
) {
const focusedRef = React.useRef(true)

useFocusEffect(
React.useCallback(() => {
focusedRef.current = true

return () => {
focusedRef.current = false
}
}, []),
)

return () => {
if (!focusedRef.current) {
return []
}

if (typeof notifyOnChangeProps === 'function') {
return notifyOnChangeProps()
}

return notifyOnChangeProps
}
}
```

In the above code, `useFocusEffect` is used to change the value of a reference that the callback will use as a condition.
## Disable queries on out of focus screens

The argument is wrapped in a reference to also guarantee that the returned callback always keeps the same reference.
If you don’t want certain queries to remain “live” while a screen is out of focus, you can use the subscribed prop on useQuery. This prop lets you control whether a query stays subscribed to updates. Combined with React Navigation’s useIsFocused, it allows you to seamlessly unsubscribe from queries when a screen isn’t in focus:

Example usage:

```tsx
function MyComponent() {
const notifyOnChangeProps = useFocusNotifyOnChangeProps()

const { dataUpdatedAt } = useQuery({
queryKey: ['myKey'],
queryFn: async () => {
const response = await fetch(
'https://api.github.com/repos/tannerlinsley/react-query',
)
return response.json()
},
notifyOnChangeProps,
})

return <Text>DataUpdatedAt: {dataUpdatedAt}</Text>
}
```

## Disable queries on out of focus screens

Enabled can also be set to a callback to support disabling queries on out of focus screens without state and re-rendering on navigation, similar to how notifyOnChangeProps works but in addition it wont trigger refetching when invalidating queries with refetchType active.

```tsx
import React from 'react'
import { useFocusEffect } from '@react-navigation/native'

export function useQueryFocusAware() {
const focusedRef = React.useRef(true)

useFocusEffect(
React.useCallback(() => {
focusedRef.current = true

return () => {
focusedRef.current = false
}
}, []),
)

return () => focusedRef.current
}
```

Example usage:
import { useIsFocused } from '@react-navigation/native'
import { useQuery } from '@tanstack/react-query'
import { Text } from 'react-native'

```tsx
function MyComponent() {
const isFocused = useQueryFocusAware()
const isFocused = useIsFocused()

const { dataUpdatedAt } = useQuery({
queryKey: ['key'],
queryFn: () => fetch(...),
enabled: isFocused,
subscribed: isFocused,
})

return <Text>DataUpdatedAt: {dataUpdatedAt}</Text>
}
```

When subscribed is false, the query unsubscribes from updates and won’t trigger re-renders or fetch new data for that screen. Once it becomes true again (e.g., when the screen regains focus), the query re-subscribes and stays up to date.
Loading