-
-
Notifications
You must be signed in to change notification settings - Fork 180
/
useAssets.ts
114 lines (99 loc) · 3.34 KB
/
useAssets.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
import {
Assets,
Cache,
} from 'pixi.js';
import { useState } from 'react';
import { UseAssetsStatus } from '../constants/UseAssetsStatus';
import { getAssetKey } from '../helpers/getAssetKey';
import type { AssetRetryState } from '../typedefs/AssetRetryState';
import type { UnresolvedAsset } from '../typedefs/UnresolvedAsset';
import type { UseAssetsOptions } from '../typedefs/UseAssetsOptions';
import type { UseAssetsResult } from '../typedefs/UseAssetsResult';
const errorCache: Map<UnresolvedAsset, AssetRetryState> = new Map();
function assetsLoadedTest<T>(asset: UnresolvedAsset<T>)
{
return Cache.has(getAssetKey(asset));
}
/** Loads assets, returning a hash of assets once they're loaded. */
export function useAssets<T = any>(
/** @description Assets to be loaded. */
assets: UnresolvedAsset[],
/** @description Asset options. */
options: UseAssetsOptions = {},
): UseAssetsResult<T>
{
const [state, setState] = useState<UseAssetsResult<T>>({
assets: Array(assets.length).fill(undefined),
isError: false,
isPending: true,
isSuccess: false,
status: UseAssetsStatus.PENDING,
});
if (typeof window === 'undefined')
{
return state;
}
const {
maxRetries = 3,
onError,
onProgress,
retryOnFailure = true,
} = options;
const allAssetsAreLoaded = assets.some(assetsLoadedTest<T>);
if (!allAssetsAreLoaded)
{
let cachedState = errorCache.get(assets);
// Rethrow the cached error if we are not retrying on failure or have reached the max retries
if (cachedState && (!retryOnFailure || cachedState.retries > maxRetries))
{
if (typeof onError === 'function')
{
onError(cachedState.error);
}
setState((previousState) => ({
...previousState,
error: cachedState?.error,
isError: true,
isPending: false,
isSuccess: false,
status: UseAssetsStatus.ERROR,
}));
}
Assets.load<T>(assets, (progressValue) =>
{
if (typeof onProgress === 'function')
{
onProgress(progressValue);
}
})
.then(() =>
{
const assetKeys = assets.map((asset: UnresolvedAsset<T>) => getAssetKey(asset));
const resolvedAssetsDictionary = Assets.get<T>(assetKeys) as Record<string, T>;
setState((previousState) => ({
...previousState,
assets: assets.map((_asset: UnresolvedAsset<T>, index: number) => resolvedAssetsDictionary[index]),
isError: false,
isPending: false,
isSuccess: true,
status: UseAssetsStatus.SUCCESS,
}));
})
.catch((error) =>
{
if (!cachedState)
{
cachedState = {
error,
retries: 0,
};
}
errorCache.set(assets, {
...cachedState,
error,
retries: cachedState.retries + 1,
});
});
}
return state;
}