├── .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 | image 29 | image 30 | image 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 | image 105 | image 106 | image 107 |
108 | ) 109 | } 110 | `} 111 |
112 |
113 | 114 |

See it in action

115 | 116 |
117 |

Status: {loaded ? 'Loaded' : 'Loading'}

118 |
119 | image 120 | image 121 | image 122 |
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 | image 29 | image 30 | image 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 | --------------------------------------------------------------------------------