├── .gitignore
├── LICENSE
├── README.md
├── example
├── lib
│ └── util.js
├── next.config.js
├── package.json
└── pages
│ └── index.js
├── package.json
├── use-images-loaded
├── .babelrc
├── .gitignore
├── .npmignore
├── README.md
├── package.json
└── src
│ ├── index.js
│ └── useImagesLoaded.js
└── yarn.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | yarn-error.log
2 |
3 | .next
4 | node_modules
5 | out
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 Faraz Khan
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## 🖼️ useImagesLoaded
2 |
3 | Custom react hook which returns true once all the images inside a container are loaded.
4 |
5 | Check out a working demo [here](https://use-images-loaded.netlify.app)
6 |
7 | ### 🚀 Getting Started
8 |
9 | #### Installation
10 |
11 | ```
12 | yarn add use-images-loaded
13 | ```
14 |
15 | #### Usage
16 |
17 | Displaying a loading indicator while images are loading in a container
18 |
19 | ```
20 | import useImageLoaded from 'use-images-loaded'
21 |
22 | const ImageContainer = () => {
23 | const [ref, loaded] = useImagesLoaded()
24 |
25 | return (
26 |
27 |
Status: {loaded ? 'Loaded': 'Loading'}
28 |

29 |

30 |

31 |
32 | )
33 | }
34 | ```
35 |
--------------------------------------------------------------------------------
/example/lib/util.js:
--------------------------------------------------------------------------------
1 | /**
2 | * toCamel
3 | * @description Convert a snake string to camel case
4 | * @via https://matthiashager.com/converting-snake-case-to-camel-case-object-keys-with-javascript
5 | */
6 |
7 | export function toCamel(str) {
8 | return str.replace(/([-_][a-z])/ig, ($1) => {
9 | return $1.toUpperCase()
10 | .replace('-', '')
11 | .replace('_', '');
12 | });
13 | }
--------------------------------------------------------------------------------
/example/next.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | exportTrailingSlash: true,
3 | exportPathMap: function() {
4 | return {
5 | '/': { page: '/' }
6 | };
7 | }
8 | };
--------------------------------------------------------------------------------
/example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "example",
3 | "version": "1.0.1",
4 | "description": "",
5 | "main": "index.js",
6 | "scripts": {
7 | "build": "next build",
8 | "dev": "next",
9 | "develop": "yarn dev",
10 | "export": "next export",
11 | "package": "yarn build && yarn export",
12 | "refresh": "yarn install --force",
13 | "start": "next start"
14 | },
15 | "keywords": [],
16 | "author": "",
17 | "license": "ISC",
18 | "dependencies": {
19 | "next": "^9.3.4",
20 | "react": "^16.13.1",
21 | "react-dom": "^16.13.1"
22 | },
23 | "private": true
24 | }
25 |
--------------------------------------------------------------------------------
/example/pages/index.js:
--------------------------------------------------------------------------------
1 | import { useImagesLoaded } from '../../use-images-loaded'
2 |
3 | import { toCamel } from '../lib/util'
4 |
5 | import hookConfig from '../../use-images-loaded/package.json'
6 |
7 | export default function Index() {
8 | const { name, description, repository = {}, author = {} } = hookConfig
9 |
10 | const { name: authorName, url: authorUrl } = author
11 |
12 | const { url: repositoryUrl } = repository
13 | const repositoryExists = typeof repositoryUrl === 'string'
14 |
15 | const repositoryUrlDisplay = repositoryExists && repositoryUrl.split('://')[1]
16 |
17 | const [ref, loaded] = useImagesLoaded()
18 |
19 | return (
20 |
21 |
74 |
75 |
76 | {toCamel(name)}
77 | {description}
78 | {repositoryExists && (
79 |
80 | {repositoryUrlDisplay}
81 |
82 | )}
83 | Installation
84 | Install with npm
85 |
86 | npm install use-images-loaded
87 |
88 | Install with yarn
89 |
90 | yard add use-images-loaded
91 |
92 | Usage
93 | Displaying a loading indicator while images are loading in a container
94 |
95 |
96 | {`import useImageLoaded from 'use-image-loaded'
97 |
98 | const ImageContainer = () => {
99 | const [ref, loaded] = useImagesLoaded()
100 |
101 | return (
102 |
103 |
Status: {loaded ? 'Loaded': 'Loading'}
104 |

105 |

106 |

107 |
108 | )
109 | }
110 | `}
111 |
112 |
113 |
114 | See it in action
115 |
116 |
117 |
Status: {loaded ? 'Loaded' : 'Loading'}
118 |
123 |
124 |
125 |
126 |
131 |
132 | )
133 | }
134 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "private": true,
3 | "workspaces": [
4 | "example",
5 | "use-images-loaded"
6 | ],
7 | "scripts": {
8 | "build": "yarn build:hook && yarn build:example",
9 | "build:example": "yarn workspace example package",
10 | "build:hook": "yarn workspace use-images-loaded build",
11 | "bump": "yarn workspace use-images-loaded bump",
12 | "develop": "yarn watch",
13 | "watch": "concurrently -n Hook,Example \"yarn watch:hook\" \"yarn watch:example\"",
14 | "watch:example": "yarn workspace example develop",
15 | "watch:hook": "yarn workspace use-images-loaded watch",
16 | "setup": "node ./scripts/setup.js"
17 | },
18 | "devDependencies": {
19 | "concurrently": "^5.1.0"
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/use-images-loaded/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": ["@babel/preset-env", "@babel/preset-react"]
3 | }
--------------------------------------------------------------------------------
/use-images-loaded/.gitignore:
--------------------------------------------------------------------------------
1 | /*.js
--------------------------------------------------------------------------------
/use-images-loaded/.npmignore:
--------------------------------------------------------------------------------
1 | yarn-error.log
2 | example
3 | node_modules
4 | src
--------------------------------------------------------------------------------
/use-images-loaded/README.md:
--------------------------------------------------------------------------------
1 | ## 🖼️ useImagesLoaded
2 |
3 | Custom react hook which returns true once all the images inside a container are loaded.
4 |
5 | Check out a working demo [here](https://use-images-loaded.netlify.app)
6 |
7 | ### 🚀 Getting Started
8 |
9 | #### Installation
10 |
11 | ```
12 | yarn add use-images-loaded
13 | ```
14 |
15 | #### Usage
16 |
17 | Displaying a loading indicator while images are loading in a container
18 |
19 | ```
20 | import useImageLoaded from 'use-images-loaded'
21 |
22 | const ImageContainer = () => {
23 | const [ref, loaded] = useImagesLoaded()
24 |
25 | return (
26 |
27 |
Status: {loaded ? 'Loaded': 'Loading'}
28 |

29 |

30 |

31 |
32 | )
33 | }
34 | ```
35 |
--------------------------------------------------------------------------------
/use-images-loaded/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "use-images-loaded",
3 | "version": "1.0.3",
4 | "description": "Returns true once all the images inside a container are loaded",
5 | "author": {
6 | "name": "Faraz Khan",
7 | "email": "farazrk001@gmail.com",
8 | "url": "https://farazkhan.me"
9 | },
10 | "keywords": [
11 | "custom",
12 | "hook",
13 | "image",
14 | "images",
15 | "onload",
16 | "load",
17 | "react",
18 | "hooks",
19 | "react-hooks"
20 | ],
21 | "main": "index.js",
22 | "scripts": {
23 | "build": "babel src --out-dir .",
24 | "bump": "npm version",
25 | "example": "cd example && yarn install && yarn package",
26 | "prepublishOnly": "yarn build",
27 | "watch": "nodemon --watch src --exec \"yarn build\""
28 | },
29 | "license": "MIT",
30 | "devDependencies": {
31 | "@babel/cli": "^7.8.4",
32 | "@babel/core": "^7.9.0",
33 | "@babel/preset-env": "^7.9.0",
34 | "@babel/preset-react": "^7.9.4",
35 | "nodemon": "^2.0.2"
36 | },
37 | "repository": {
38 | "type": "git",
39 | "url": "https://github.com/frzkn/use-images-loaded"
40 | },
41 | "bugs": {
42 | "url": "https://github.com/frzkn/use-images-loaded/issues"
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/use-images-loaded/src/index.js:
--------------------------------------------------------------------------------
1 | export { default as useImagesLoaded } from './useImagesLoaded';
--------------------------------------------------------------------------------
/use-images-loaded/src/useImagesLoaded.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 | import { useEffect, useState } from 'react'
3 |
4 | const useImagesLoaded = () => {
5 | const [ref, setRef] = useState(null)
6 | const [imagesLoaded, setImagesLoaded] = useState(false)
7 |
8 | useEffect(() => {
9 | if (!ref) return
10 | const resolveReference = []
11 | const imageElements = ref.getElementsByTagName('img')
12 | const promisesArray = [...imageElements].map((img) => {
13 | if (!img.complete) {
14 | return new Promise((resolve) => {
15 | resolveReference.push(resolve)
16 | img.addEventListener('load', resolve, { once: true })
17 | })
18 | } else return null
19 | })
20 | if (promisesArray.length > 0) {
21 | Promise.all(promisesArray).then(() => {
22 | setImagesLoaded(true)
23 | })
24 | }
25 |
26 | return () => {
27 | imageElements.forEach((img, index) => {
28 | console.log(resolveReference)
29 | img.removeEventListener('load', resolveReference[index])
30 | })
31 | }
32 | }, [ref])
33 | return [setRef, imagesLoaded]
34 | }
35 |
36 | export default useImagesLoaded
37 |
--------------------------------------------------------------------------------