From e0ec445a1e09defd60540b0f436e9fc797a4c4c8 Mon Sep 17 00:00:00 2001 From: erdoganoksuz Date: Thu, 2 Jul 2020 16:38:35 +0300 Subject: [PATCH] lazy load example added --- package.json | 7 ++- src/App.css | 41 ++++--------- src/App.test.tsx | 9 --- src/App.tsx | 26 ++++---- src/index.css | 13 ---- src/index.tsx | 5 +- src/lazy.tsx | 31 ++++++++++ src/logo.svg | 7 --- src/serviceWorker.ts | 143 ------------------------------------------- tsconfig.json | 4 +- yarn.lock | 14 ++++- 11 files changed, 78 insertions(+), 222 deletions(-) delete mode 100644 src/App.test.tsx delete mode 100644 src/index.css create mode 100644 src/lazy.tsx delete mode 100644 src/logo.svg delete mode 100644 src/serviceWorker.ts diff --git a/package.json b/package.json index 8efaa98..4edc960 100644 --- a/package.json +++ b/package.json @@ -1,12 +1,14 @@ { "name": "react-lazy-images", "version": "0.1.0", + "source": "src/App.tsx", "private": true, "dependencies": { "@types/jest": "24.0.18", "@types/node": "12.7.5", "@types/react": "16.9.2", "@types/react-dom": "16.9.0", + "faker": "^4.1.0", "react": "^16.9.0", "react-dom": "^16.9.0", "react-scripts": "3.1.1", @@ -32,5 +34,8 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "devDependencies": { + "@types/faker": "^4.1.5" } -} +} \ No newline at end of file diff --git a/src/App.css b/src/App.css index b41d297..f5ecd52 100644 --- a/src/App.css +++ b/src/App.css @@ -1,33 +1,16 @@ -.App { - text-align: center; +.App-header{ + display: flex; + height: 100vh; + align-items: center; + justify-content: center; } -.App-logo { - animation: App-logo-spin infinite 20s linear; - height: 40vmin; - pointer-events: none; +.container{ + width: 600px; + display: flex; + overflow: scroll; } -.App-header { - background-color: #282c34; - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - font-size: calc(10px + 2vmin); - color: white; -} - -.App-link { - color: #61dafb; -} - -@keyframes App-logo-spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} +img{ + margin-right: 10px; +} \ No newline at end of file diff --git a/src/App.test.tsx b/src/App.test.tsx deleted file mode 100644 index a754b20..0000000 --- a/src/App.test.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom'; -import App from './App'; - -it('renders without crashing', () => { - const div = document.createElement('div'); - ReactDOM.render(, div); - ReactDOM.unmountComponentAtNode(div); -}); diff --git a/src/App.tsx b/src/App.tsx index 226ee63..d3ad5b4 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -1,23 +1,23 @@ import React from 'react'; -import logo from './logo.svg'; import './App.css'; +import Lazy from './lazy'; const App: React.FC = () => { + const placeholder="https://picsum.photos/id/237/500/300" + + const generateImg=()=>`https://picsum.photos/id/${Math.floor(Math.random() * 999)}/500/300` + return (
- logo -

- Edit src/App.tsx and save to reload. -

- - Learn React - +
+ + + + + + +
); diff --git a/src/index.css b/src/index.css deleted file mode 100644 index ec2585e..0000000 --- a/src/index.css +++ /dev/null @@ -1,13 +0,0 @@ -body { - margin: 0; - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -code { - font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New', - monospace; -} diff --git a/src/index.tsx b/src/index.tsx index 87d1be5..400c3eb 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,12 +1,11 @@ import React from 'react'; import ReactDOM from 'react-dom'; -import './index.css'; + import App from './App'; -import * as serviceWorker from './serviceWorker'; ReactDOM.render(, document.getElementById('root')); // If you want your app to work offline and load faster, you can change // unregister() to register() below. Note this comes with some pitfalls. // Learn more about service workers: https://bit.ly/CRA-PWA -serviceWorker.unregister(); + diff --git a/src/lazy.tsx b/src/lazy.tsx new file mode 100644 index 0000000..3316dc9 --- /dev/null +++ b/src/lazy.tsx @@ -0,0 +1,31 @@ +import React, { useState, useRef } from 'react'; + +function Lazy(props: { placeholder: string; src: string; ratio: number; className?: string; force?: boolean; onVisible?: Function }) { + const [currentSrc, setCurrentSrc] = useState(props.force ? props.src : props.placeholder); + const el = useRef(null); + + const handleChange = ([root]: any, ) => { + if (root.intersectionRatio > Number(props.ratio) && root.isIntersecting === true) { + setCurrentSrc(props.src); + observer.disconnect(); + if (props.onVisible) props.onVisible(); + } + } + + const observer = new IntersectionObserver(handleChange, { threshold: props.ratio }); + + const handleObserve = () => { + observer.observe(el.current as any); + } + + return (); +} + +export default Lazy; + + diff --git a/src/logo.svg b/src/logo.svg deleted file mode 100644 index 6b60c10..0000000 --- a/src/logo.svg +++ /dev/null @@ -1,7 +0,0 @@ - - - - - - - diff --git a/src/serviceWorker.ts b/src/serviceWorker.ts deleted file mode 100644 index 15d90cb..0000000 --- a/src/serviceWorker.ts +++ /dev/null @@ -1,143 +0,0 @@ -// This optional code is used to register a service worker. -// register() is not called by default. - -// This lets the app load faster on subsequent visits in production, and gives -// it offline capabilities. However, it also means that developers (and users) -// will only see deployed updates on subsequent visits to a page, after all the -// existing tabs open on the page have been closed, since previously cached -// resources are updated in the background. - -// To learn more about the benefits of this model and instructions on how to -// opt-in, read https://bit.ly/CRA-PWA - -const isLocalhost = Boolean( - window.location.hostname === 'localhost' || - // [::1] is the IPv6 localhost address. - window.location.hostname === '[::1]' || - // 127.0.0.1/8 is considered localhost for IPv4. - window.location.hostname.match( - /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/ - ) -); - -type Config = { - onSuccess?: (registration: ServiceWorkerRegistration) => void; - onUpdate?: (registration: ServiceWorkerRegistration) => void; -}; - -export function register(config?: Config) { - if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) { - // The URL constructor is available in all browsers that support SW. - const publicUrl = new URL( - (process as { env: { [key: string]: string } }).env.PUBLIC_URL, - window.location.href - ); - if (publicUrl.origin !== window.location.origin) { - // Our service worker won't work if PUBLIC_URL is on a different origin - // from what our page is served on. This might happen if a CDN is used to - // serve assets; see https://github.com/facebook/create-react-app/issues/2374 - return; - } - - window.addEventListener('load', () => { - const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`; - - if (isLocalhost) { - // This is running on localhost. Let's check if a service worker still exists or not. - checkValidServiceWorker(swUrl, config); - - // Add some additional logging to localhost, pointing developers to the - // service worker/PWA documentation. - navigator.serviceWorker.ready.then(() => { - console.log( - 'This web app is being served cache-first by a service ' + - 'worker. To learn more, visit https://bit.ly/CRA-PWA' - ); - }); - } else { - // Is not localhost. Just register service worker - registerValidSW(swUrl, config); - } - }); - } -} - -function registerValidSW(swUrl: string, config?: Config) { - navigator.serviceWorker - .register(swUrl) - .then(registration => { - registration.onupdatefound = () => { - const installingWorker = registration.installing; - if (installingWorker == null) { - return; - } - installingWorker.onstatechange = () => { - if (installingWorker.state === 'installed') { - if (navigator.serviceWorker.controller) { - // At this point, the updated precached content has been fetched, - // but the previous service worker will still serve the older - // content until all client tabs are closed. - console.log( - 'New content is available and will be used when all ' + - 'tabs for this page are closed. See https://bit.ly/CRA-PWA.' - ); - - // Execute callback - if (config && config.onUpdate) { - config.onUpdate(registration); - } - } else { - // At this point, everything has been precached. - // It's the perfect time to display a - // "Content is cached for offline use." message. - console.log('Content is cached for offline use.'); - - // Execute callback - if (config && config.onSuccess) { - config.onSuccess(registration); - } - } - } - }; - }; - }) - .catch(error => { - console.error('Error during service worker registration:', error); - }); -} - -function checkValidServiceWorker(swUrl: string, config?: Config) { - // Check if the service worker can be found. If it can't reload the page. - fetch(swUrl) - .then(response => { - // Ensure service worker exists, and that we really are getting a JS file. - const contentType = response.headers.get('content-type'); - if ( - response.status === 404 || - (contentType != null && contentType.indexOf('javascript') === -1) - ) { - // No service worker found. Probably a different app. Reload the page. - navigator.serviceWorker.ready.then(registration => { - registration.unregister().then(() => { - window.location.reload(); - }); - }); - } else { - // Service worker found. Proceed as normal. - registerValidSW(swUrl, config); - } - }) - .catch(() => { - console.log( - 'No internet connection found. App is running in offline mode.' - ); - }); -} - -export function unregister() { - if ('serviceWorker' in navigator) { - navigator.serviceWorker.ready.then(registration => { - registration.unregister(); - }); - } -} diff --git a/tsconfig.json b/tsconfig.json index f2850b7..65be953 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -20,6 +20,6 @@ "jsx": "react" }, "include": [ - "src" + "src/lazy.tsx" ] -} +} \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index f06a39f..76ad8c5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1325,6 +1325,11 @@ resolved "https://registry.yarnpkg.com/@types/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#1ee30d79544ca84d68d4b3cdb0af4f205663dd2d" integrity sha512-OCutwjDZ4aFS6PB1UZ988C4YgwlBHJd6wCeQqaLdmadZ/7e+w79+hbMUFC1QXDNCmdyoRfAFdm0RypzwR+Qpag== +"@types/faker@^4.1.5": + version "4.1.5" + resolved "https://registry.yarnpkg.com/@types/faker/-/faker-4.1.5.tgz#8f620f9c9a67150aa0a32b4e8a407da43fca61d4" + integrity sha512-YSDqoBEWYGdNk53xSkkb6REaUaVSlIjxIAGjj/nbLzlZOit7kUU+nA2zC2qQkIVO4MQ+3zl4Sz7aw+kbpHHHUQ== + "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0": version "2.0.1" resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz#42995b446db9a48a11a07ec083499a860e9138ff" @@ -4173,6 +4178,11 @@ extsprintf@^1.2.0: resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= +faker@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/faker/-/faker-4.1.0.tgz#1e45bbbecc6774b3c195fad2835109c6d748cc3f" + integrity sha1-HkW7vsxndLPBlfrSg1EJxtdIzD8= + fast-deep-equal@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" @@ -8263,7 +8273,7 @@ react-dev-utils@^9.0.3: strip-ansi "5.2.0" text-table "0.2.0" -react-dom@16.9.0: +react-dom@^16.9.0: version "16.9.0" resolved "https://registry.yarnpkg.com/react-dom/-/react-dom-16.9.0.tgz#5e65527a5e26f22ae3701131bcccaee9fb0d3962" integrity sha512-YFT2rxO9hM70ewk9jq0y6sQk8cL02xm4+IzYBz75CQGlClQQ1Bxq0nhHF6OtSbit+AIahujJgb/CPRibFkMNJQ== @@ -8349,7 +8359,7 @@ react-scripts@3.1.1: optionalDependencies: fsevents "2.0.7" -react@16.9.0: +react@^16.9.0: version "16.9.0" resolved "https://registry.yarnpkg.com/react/-/react-16.9.0.tgz#40ba2f9af13bc1a38d75dbf2f4359a5185c4f7aa" integrity sha512-+7LQnFBwkiw+BobzOF6N//BdoNw0ouwmSJTEm9cglOOmsg/TMiFHZLe2sEoN5M7LgJTj9oHH0gxklfnQe66S1w==