Skip to content

Commit

Permalink
feat: new Hook useReFocus to run a callback when re-focus
Browse files Browse the repository at this point in the history
  • Loading branch information
vikiboss committed Aug 5, 2024
1 parent 772aba0 commit 88cc9f2
Show file tree
Hide file tree
Showing 4 changed files with 195 additions and 0 deletions.
19 changes: 19 additions & 0 deletions src/use-re-focus/demo.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { Card } from '@/components'
import { useReFocus } from '@shined/react-use'
import { Toaster, toast } from 'react-hot-toast'

export function App() {
useReFocus(
() => {
toast.success('Refocused')
},
{ wait: 6000 },
)

return (
<Card>
<div>This component will show a toast when the user refocuses on the window.</div>
<Toaster />
</Card>
)
}
51 changes: 51 additions & 0 deletions src/use-re-focus/index.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# useReFocus

import { HooksType, NotReleased } from '@/components'

<HooksType category="Utilities" lowLevel />

<NotReleased />

A React Hook that helps to run a function when the page is refocused.

## Demo

import { App } from './demo'

<App />

## Usage

import { RawCode } from '@/components'
import source from '!!raw-loader!./demo'

<RawCode>{source}</RawCode>

## Source

import { Source } from '@/components'

<Source />

## API

```tsx
useReFocus(fn, options): void
```

### Fn

A function that will be called when the page is refocused.

### Options

```tsx
interface UseReFocusOptions extends UseThrottledFnOptions {
/**
* Register focus event listener.
*/
registerReFocus?: (callback: AnyFunc) => void
}
```

See [useThrottledFn](/reference/use-throttled-fn) for more information.
74 changes: 74 additions & 0 deletions src/use-re-focus/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { useEffectOnce } from '../use-effect-once'
import { useLatest } from '../use-latest'
import { useThrottledFn } from '../use-throttled-fn'

import type { UseThrottledFnOptions } from '../use-throttled-fn'
import type { AnyFunc } from '../utils/basic'

interface UseReFocusOptions extends UseThrottledFnOptions {
/**
* Register focus event listener.
*/
registerReFocus?: (callback: AnyFunc) => void
}

export function registerWebReFocus(callback: AnyFunc) {
const focusState = { current: false }

function handleFocus() {
const nextState = true

if (!focusState.current) {
callback()
focusState.current = nextState
}
}

function handleBlur() {
const nextState = false
focusState.current = nextState
}

window.addEventListener('focus', handleFocus, { passive: true })
window.addEventListener('blur', handleBlur, { passive: true })

return () => {
window.removeEventListener('focus', handleFocus)
window.removeEventListener('blur', handleBlur)
}
}

export function useReFocus(callback: AnyFunc, options: UseReFocusOptions = {}) {
const { registerReFocus = registerWebReFocus, ...throttleOptions } = options

const throttledFn = useThrottledFn(callback, {
leading: true,
trailing: false,
...throttleOptions,
})

const latest = useLatest({ throttledFn })

useEffectOnce(() => {
return registerReFocus(() => latest.current.throttledFn())
})
}

// biome-ignore lint/suspicious/noExplicitAny: ignore appState type
export function createReactNativeReFocusRegister(appState: any) {
return function registerReactNativeReFocus(callback: AnyFunc) {
let state = appState.currentState

const onAppStateChange = (nextAppState: string) => {
if (state.match(/inactive|background/) && nextAppState === 'active') {
callback()
}

state = nextAppState
}

const subscription = appState.addEventListener('change', onAppStateChange)

return () => subscription.remove()
}
}
51 changes: 51 additions & 0 deletions src/use-re-focus/index_zh-cn.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
# useReFocus

import { HooksType, NotReleased } from '@/components'

<HooksType category="Utilities" lowLevel />

<NotReleased />

这是一个 React 钩子(Hook),用于在**重新**获得焦点时运行一个函数。

## 演示 Demo \{#demo}

import { App } from './demo'

<App />

## 用法 Usage \{#usage}

import { RawCode } from '@/components'
import source from '!!raw-loader!./demo'

<RawCode>{source}</RawCode>

## 源码 Source \{#source}

import { Source } from '@/components'

<Source />

## API \{#api}

```tsx
useReFocus(fn, options): void
```

### 函数 Fn \{#fn}

当重新获得焦点时将被调用的函数。

### 选项 Options \{#options}

```tsx
interface UseReFocusOptions extends UseThrottledFnOptions {
/**
* 注册焦点事件监听器。
*/
registerReFocus?: (callback: AnyFunc) => void
}
```

查看 [useThrottledFn](/reference/use-throttled-fn) 以了解更多信息。

0 comments on commit 88cc9f2

Please sign in to comment.