Skip to content

Commit

Permalink
refactor: use useAsync from react-hooz instead of useAsyncFn from rea…
Browse files Browse the repository at this point in the history
…ct-use
  • Loading branch information
arianrhodsandlot committed Oct 20, 2023
1 parent 013de4a commit 1194296
Show file tree
Hide file tree
Showing 8 changed files with 87 additions and 68 deletions.
10 changes: 5 additions & 5 deletions src/views/components/common/cloud-service-login-button.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useIntervalEffect } from '@react-hookz/web'
import { useAsync as useAsyncFn, useIntervalEffect } from '@react-hookz/web'
import clsx from 'clsx'
import mitt from 'mitt'
import { useRef, useState } from 'react'
import { useAsync, useAsyncFn } from 'react-use'
import { useAsync } from 'react-use'
import { type CloudService, detectNeedsLogin, getAuthorizeUrl, getTokenStorageKey } from '../../../core'
import { BaseButton } from '../primitives/base-button'
import { ReturnToHomeButton } from './return-to-home-button'
Expand Down Expand Up @@ -46,7 +46,7 @@ export function CloudServiceLoginButton({
}
}, 100)

const [needsLoginState, checkNeedsLogin] = useAsyncFn(async () => {
const [needsLoginState, { execute: checkNeedsLogin }] = useAsyncFn(async () => {
const promise = new Promise<boolean>((resolve) => {
async function onStorage(event: StorageEvent) {
if (event.key === getTokenStorageKey(cloudService)) {
Expand Down Expand Up @@ -84,8 +84,8 @@ export function CloudServiceLoginButton({
}
}

const loginPending = needsLoginState.loading || isAuthWindowOpening
const loginSuccess = !needsLoginState.loading && needsLoginState.value === false
const loginPending = needsLoginState.status === 'loading' || isAuthWindowOpening
const loginSuccess = needsLoginState.status !== 'loading' && needsLoginState.result === false
const showLoading = loginPending || loginSuccess

if (showLoading) {
Expand Down
30 changes: 28 additions & 2 deletions src/views/components/home-screen/game-entries-grid/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import delay from 'delay'
import { useCallback, useEffect, useRef } from 'react'
import { isEqual, map, omit } from 'lodash-es'
import { memo, useCallback, useEffect, useRef } from 'react'
import { FixedSizeGrid } from 'react-window'
import { type Rom } from '../../../../core'
import { isFocusingHome } from '../utils'
Expand All @@ -10,7 +11,7 @@ interface GameEntryGridProps extends Omit<FixedSizeGrid['props'], 'children'> {
roms: Rom[]
}

export function GameEntryGrid({ roms, ...props }: GameEntryGridProps) {
function GameEntryGrid({ roms, ...props }: GameEntryGridProps) {
const innerRef = useRef<HTMLDivElement>()
const { rowCount, columnCount } = props

Expand Down Expand Up @@ -40,3 +41,28 @@ export function GameEntryGrid({ roms, ...props }: GameEntryGridProps) {
</FixedSizeGrid>
) : null
}

// do not rerender when ROMs from server are the same as those from cache
function propsAreEqual(prevProps: GameEntryGridProps, nextProps: GameEntryGridProps) {
if (prevProps === nextProps) {
return true
}

if (!isEqual(omit(prevProps, 'roms'), omit(nextProps, 'roms'))) {
return false
}

const prevRoms = prevProps.roms
const nextRoms = nextProps.roms
if (prevRoms.length !== nextRoms.length) {
return false
}

const prevRomsIds = map(prevRoms, 'id')
const nextRomsIds = map(nextRoms, 'id')
return prevRomsIds.join(',') === nextRomsIds.join(',')
}

const MemorizedGameEntryGrid = memo(GameEntryGrid, propsAreEqual)

export { MemorizedGameEntryGrid as GameEntryGrid }
14 changes: 7 additions & 7 deletions src/views/components/home-screen/game-menus/menu-overlay.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useAsync as useAsyncFn } from '@react-hookz/web'
import { useSetAtom } from 'jotai'
import { useAsyncFn } from 'react-use'
import { loadGameState, restartGame, resumeGame, saveGameState } from '../../../../core'
import { showMenuOverlayAtom } from '../../atoms'
import { BouncingEllipsis } from '../../common/bouncing-ellipsis'
Expand All @@ -12,17 +12,17 @@ export function MenuOverlay() {
const setShowMenuOverlay = useSetAtom(showMenuOverlayAtom)
const { exit } = useExit()

const [saveStateState, saveState] = useAsyncFn(async () => {
if (saveStateState.loading) {
const [saveStateState, { execute: saveState }] = useAsyncFn(async () => {
if (saveStateState.status === 'loading') {
return
}
await saveGameState()
resumeGame()
setShowMenuOverlay(false)
})

const [loadStateState, loadState] = useAsyncFn(async (stateId: string) => {
if (loadStateState.loading) {
const [loadStateState, { execute: loadState }] = useAsyncFn(async (stateId: string) => {
if (loadStateState.status === 'loading') {
return
}
await loadGameState(stateId)
Expand All @@ -47,11 +47,11 @@ export function MenuOverlay() {

return (
<div className='menu-overlay h-full w-full py-10' data-testid='menu-overlay'>
{saveStateState.loading ? (
{saveStateState.status === 'loading' ? (
<LoadingScreen>
Saving <BouncingEllipsis /> Please do not turn off your device!
</LoadingScreen>
) : loadStateState.loading ? (
) : loadStateState.status === 'loading' ? (
<LoadingScreen>
Loading selected state
<BouncingEllipsis />
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { useAsync } from '@react-hookz/web'
import { clsx } from 'clsx'
import { useAtom } from 'jotai'
import { useEffect } from 'react'
import { useAsyncFn } from 'react-use'
import { type CloudService } from '../../../../core'
import { directoyTreeAtom } from './atoms'
import { type TreeNode } from './types'
Expand All @@ -16,15 +16,15 @@ interface DirectoryTreeNodeParams {
export function DirectoryTreeNode({ node, cloudService, onSelect }: DirectoryTreeNodeParams) {
const [tree, setTree] = useAtom(directoyTreeAtom)

const [state, updateTree] = useAsyncFn(async () => {
const [state, { execute: updateTree }] = useAsync(async () => {
if (tree) {
await toggleNodeExpanded({ node, cloudService })
setTree({ ...tree })
}
})

function onClickDirectoryName() {
if (state.loading === false) {
if (state.status !== 'loading') {
updateTree()
}
}
Expand Down Expand Up @@ -82,7 +82,9 @@ export function DirectoryTreeNode({ node, cloudService, onSelect }: DirectoryTre
</div>
</div>

{state.loading ? <span className='icon-[line-md--loading-loop] my-2 ml-10 h-6 w-6 text-rose-700' /> : null}
{state.status === 'loading' ? (
<span className='icon-[line-md--loading-loop] my-2 ml-10 h-6 w-6 text-rose-700' />
) : null}

{node.expanded ? (
<div className='pl-6'>
Expand Down
27 changes: 12 additions & 15 deletions src/views/components/setup-wizard/dropbox-button/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useAsync } from '@react-hookz/web'
import { useAtomValue, useSetAtom } from 'jotai'
import { useAsyncFn } from 'react-use'
import { updatePreference, validateRomDirectory } from '../../../../core'
import { BaseButton } from '../../primitives/base-button'
import { BaseDialogTrigger } from '../../primitives/base-dialog-trigger'
Expand All @@ -10,26 +10,23 @@ export function DropboxButton() {
const onSetup = useAtomValue(onSetupAtom)
const setIsInvalidDialogOpen = useSetAtom(isInvalidDialogOpenAtom)

const [state, onSelect] = useAsyncFn(
async (romDirectory: string) => {
const isValid = await validateRomDirectory({ directory: romDirectory, type: 'dropbox' })
const [state, { execute: onSelect }] = useAsync(async (romDirectory: string) => {
const isValid = await validateRomDirectory({ directory: romDirectory, type: 'dropbox' })

if (isValid) {
await updatePreference({ fileSystem: 'dropbox', directory: romDirectory })
onSetup?.()
setIsInvalidDialogOpen(false)
} else {
setIsInvalidDialogOpen(true)
}
},
[onSetup],
)
if (isValid) {
await updatePreference({ fileSystem: 'dropbox', directory: romDirectory })
onSetup?.()
setIsInvalidDialogOpen(false)
} else {
setIsInvalidDialogOpen(true)
}
})

return (
<BaseDialogTrigger
content={
<div className='w-96 max-w-full'>
<DropboxDirectoryPicker isValidating={state.loading} onSelect={onSelect} />
<DropboxDirectoryPicker isValidating={state.status === 'loading'} onSelect={onSelect} />
</div>
}
>
Expand Down
27 changes: 12 additions & 15 deletions src/views/components/setup-wizard/google-drive-button/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useAsync } from '@react-hookz/web'
import { useAtomValue, useSetAtom } from 'jotai'
import { useAsyncFn } from 'react-use'
import { updatePreference, validateRomDirectory } from '../../../../core'
import { BaseButton } from '../../primitives/base-button'
import { BaseDialogTrigger } from '../../primitives/base-dialog-trigger'
Expand All @@ -10,26 +10,23 @@ export function GoogleDriveButton() {
const onSetup = useAtomValue(onSetupAtom)
const setIsInvalidDialogOpen = useSetAtom(isInvalidDialogOpenAtom)

const [state, onSelect] = useAsyncFn(
async (romDirectory: string) => {
const isValid = await validateRomDirectory({ directory: romDirectory, type: 'google-drive' })
const [state, { execute: onSelect }] = useAsync(async (romDirectory: string) => {
const isValid = await validateRomDirectory({ directory: romDirectory, type: 'google-drive' })

if (isValid) {
await updatePreference({ fileSystem: 'google-drive', directory: romDirectory })
onSetup?.()
setIsInvalidDialogOpen(false)
} else {
setIsInvalidDialogOpen(true)
}
},
[onSetup],
)
if (isValid) {
await updatePreference({ fileSystem: 'google-drive', directory: romDirectory })
onSetup?.()
setIsInvalidDialogOpen(false)
} else {
setIsInvalidDialogOpen(true)
}
})

return (
<BaseDialogTrigger
content={
<div className='w-96 max-w-full'>
<GoogleDriveDirectoryPicker isValidating={state.loading} onSelect={onSelect} />
<GoogleDriveDirectoryPicker isValidating={state.status === 'loading'} onSelect={onSelect} />
</div>
}
>
Expand Down
10 changes: 5 additions & 5 deletions src/views/components/setup-wizard/local-file-button.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { useAsync } from '@react-hookz/web'
import fileSelect from 'file-select'
import { useAtomValue, useSetAtom } from 'jotai'
import { useAsyncFn } from 'react-use'
import { getSupportedFileExtensions, previewGame } from '../../../core'
import { isGameLaunchedAtom, isGameRunningAtom } from '../atoms'
import { BouncingEllipsis } from '../common/bouncing-ellipsis'
Expand All @@ -20,7 +20,7 @@ export function LocalFileButton() {
const { mayNeedsUserInteraction, showInteractionButton, onUserInteract, waitForUserInteraction } =
useUserInteraction()

const [state, run] = useAsyncFn(async () => {
const [state, { execute }] = useAsync(async () => {
const file: File = await fileSelect({
accept: supportedFileExtensions.map((extension) => `.${extension}`),
})
Expand All @@ -34,16 +34,16 @@ export function LocalFileButton() {
})

function onClick() {
if (!state.loading) {
run()
if (state.status !== 'loading') {
execute()
}
}

return (
<>
<BaseButton className='w-60' data-testid='select-a-rom' onClick={onClick}>
<span className='icon-[mdi--zip-box-outline] h-5 w-5' />
{state.loading ? (
{state.status === 'loading' ? (
<>
Loading
<BouncingEllipsis />
Expand Down
27 changes: 12 additions & 15 deletions src/views/components/setup-wizard/onedrive-button/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { useAsync } from '@react-hookz/web'
import { useAtomValue, useSetAtom } from 'jotai'
import { useAsyncFn } from 'react-use'
import { updatePreference, validateRomDirectory } from '../../../../core'
import { BaseButton } from '../../primitives/base-button'
import { BaseDialogTrigger } from '../../primitives/base-dialog-trigger'
Expand All @@ -10,26 +10,23 @@ export function OnedriveButton() {
const onSetup = useAtomValue(onSetupAtom)
const setIsInvalidDialogOpen = useSetAtom(isInvalidDialogOpenAtom)

const [state, onSelect] = useAsyncFn(
async (romDirectory: string) => {
const isValid = await validateRomDirectory({ directory: romDirectory, type: 'onedrive' })
const [state, { execute: onSelect }] = useAsync(async (romDirectory: string) => {
const isValid = await validateRomDirectory({ directory: romDirectory, type: 'onedrive' })

if (isValid) {
await updatePreference({ fileSystem: 'onedrive', directory: romDirectory })
onSetup?.()
setIsInvalidDialogOpen(false)
} else {
setIsInvalidDialogOpen(true)
}
},
[onSetup],
)
if (isValid) {
await updatePreference({ fileSystem: 'onedrive', directory: romDirectory })
onSetup?.()
setIsInvalidDialogOpen(false)
} else {
setIsInvalidDialogOpen(true)
}
})

return (
<BaseDialogTrigger
content={
<div className='w-96 max-w-full'>
<OnedriveDirectoryPicker isValidating={state.loading} onSelect={onSelect} />
<OnedriveDirectoryPicker isValidating={state.status === 'loading'} onSelect={onSelect} />
</div>
}
>
Expand Down

0 comments on commit 1194296

Please sign in to comment.