🥅
Reactでネットワークのオフライン/オンラインを検知するカスタムhooks
記事にするほどの内容ではないですが作業ログ的に残しておきます。
やりたいこと
下記のハンドリングができるReact hooksを作りたいです。
- ブラウザでネットワークがオフラインになったときにエラー表示を出したい
- オンラインになったらエラー表示を消したい
オフライン/オンラインイベント
オフライン/オンラインになったときに発火するイベントがありましたので、これを使います。
また、オンラインかどうかの状態を返すプロパティがあったのでこれも使います。
コード
useState
を使って再レンダリングさせるようにします。
import { useEffect, useState } from 'react'
const useOffline = () => {
const [isOffline, setIsOffline] = useState(!window.navigator.onLine)
// add event listener
const onOffline = () => {
setIsOffline(true)
}
const onOnline = () => {
setIsOffline(false)
}
useEffect(() => {
window.addEventListener('offline', onOffline)
window.addEventListener('online', onOnline)
return () => {
// remove event listener
window.removeEventListener('offline', onOffline)
window.removeEventListener('online', onOnline)
}
}, [])
return {
isOffline,
}
}
export default useOffline
ついでにテストコード
Jestでのテストコードも書いたので載せておきます。
import { act, renderHook } from '@testing-library/react'
import useOffline from './useOffline'
describe('useOfflineのテスト', () => {
// イベントを発火させるためのヘルパー関数です
const fireOnlineOfflineEvent = (type) => {
const event = new Event(type)
window.dispatchEvent(event)
}
it('オフライン/オンラインになったとき値を返す', () => {
const { result, rerender } = renderHook(() => useOffline())
expect(result.current.isOffline).toBe(false)
// offline イベントをシミュレート
act(() => {
fireOnlineOfflineEvent('offline')
rerender()
})
expect(result.current.isOffline).toBe(true)
// online イベントをシミュレート
act(() => {
fireOnlineOfflineEvent('online')
rerender()
})
expect(result.current.isOffline).toBe(false)
})
it('アンマウントされるときにクリーン処理が走る', () => {
const removeEventListenerSpy = jest.spyOn(window, 'removeEventListener')
const { unmount } = renderHook(() => useOffline())
unmount()
expect(removeEventListenerSpy).toHaveBeenCalledWith(
'offline',
expect.any(Function)
)
expect(removeEventListenerSpy).toHaveBeenCalledWith(
'online',
expect.any(Function)
)
})
})
Discussion