about summary refs log tree commit diff
path: root/src/view/com/lightbox/ImageViewing/hooks/useImageDimensions.ts
blob: 46f9f22953803ad4e2ffd86ae068437c7aaf4e59 (plain) (blame)
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
/**
 * Copyright (c) JOB TODAY S.A. and its affiliates.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 */

import {useEffect, useState} from 'react'
import {Image, ImageURISource} from 'react-native'

import {Dimensions, ImageSource} from '../@types'

const CACHE_SIZE = 50

type CacheStorageItem = {key: string; value: any}

const createCache = (cacheSize: number) => ({
  _storage: [] as CacheStorageItem[],
  get(key: string): any {
    const {value} =
      this._storage.find(({key: storageKey}) => storageKey === key) || {}

    return value
  },
  set(key: string, value: any) {
    if (this._storage.length >= cacheSize) {
      this._storage.shift()
    }

    this._storage.push({key, value})
  },
})

const imageDimensionsCache = createCache(CACHE_SIZE)

const useImageDimensions = (image: ImageSource): Dimensions | null => {
  const [dimensions, setDimensions] = useState<Dimensions | null>(null)

  // eslint-disable-next-line @typescript-eslint/no-shadow
  const getImageDimensions = (image: ImageSource): Promise<Dimensions> => {
    return new Promise(resolve => {
      if (image.uri) {
        const source = image as ImageURISource
        const cacheKey = source.uri as string
        const imageDimensions = imageDimensionsCache.get(cacheKey)
        if (imageDimensions) {
          resolve(imageDimensions)
        } else {
          Image.getSizeWithHeaders(
            // @ts-ignore
            source.uri,
            source.headers,
            (width: number, height: number) => {
              imageDimensionsCache.set(cacheKey, {width, height})
              resolve({width, height})
            },
            () => {
              resolve({width: 0, height: 0})
            },
          )
        }
      } else {
        resolve({width: 0, height: 0})
      }
    })
  }

  let isImageUnmounted = false

  useEffect(() => {
    // eslint-disable-next-line @typescript-eslint/no-shadow
    getImageDimensions(image).then(dimensions => {
      if (!isImageUnmounted) {
        setDimensions(dimensions)
      }
    })

    return () => {
      // eslint-disable-next-line react-hooks/exhaustive-deps
      isImageUnmounted = true
    }
  }, [image])

  return dimensions
}

export default useImageDimensions