console.log(1);
setTimeout(() => console.log(2), 0);
console.log(3);
?
- Web API docs
Provides a way to asynchronously observe changes in the intersection of a target element with an ancestor element or with a top-level document's viewport
import { useState, useEffect, RefObject } from 'react';
export const useVisible = (
ref: RefObject<HTMLDivElement>,
options = {
root: null,
rootMargin: '0px',
threshold: 1.0
}
) => {
const [isVisible, setIsVisible] = useState<boolean>(false);
useEffect(() => {
const { current: elementRef } = ref;
if (elementRef) {
const observer = new IntersectionObserver(
([entry]) => setIsVisible(entry.isIntersecting), options
);
observer.observe(elementRef);
return () => observer.unobserve(elementRef);
}
}, [ref, options]);
return isVisible;
};
Lazy-load images
Infinite scroll lists
Defer animations
Save compute power
03
02
04
01
Provides events you can watch for to know the current visibility state of the page
Triggers when user
switches tab
minimizes window
puts another window as overlay
locks/turns off device
import { useEffect, useState } from "react";
export const usePageVisibility = () => {
const [pageVisible, setPageVisible] = useState<boolean>(true);
useEffect(() => {
const handleVisibilityChange = () => {
const isPageVisible = document.visibilityState === "visible";
setPageVisible(isPageVisible);
};
document.addEventListener("visibilitychange", handleVisibilityChange);
return () => {
document.removeEventListener("visibilitychange", handleVisibilityChange);
};
}, []);
return pageVisible;
};
Improving performance
01
Pause audio/video
02
Detect page visit count
03
Poll server data
04
Carousel
05
Prevent devices from locking the screen when an application needs to keep running
Only visible (active) documents can acquire the screen wake lock
import { useEffect, useCallback, useRef } from 'react';
export const useWakeLock = (shouldWakeLock = false) => {
let sentinel = useRef<WakeLockSentinel | null>(null);
const requestWakeLockSentinel = useCallback(async () => {
sentinel.current = await navigator.wakeLock.request('screen');
}, []);
const releaseWakeLockSentinel = useCallback(async () => {
await sentinel.current?.release();
sentinel.current = null;
}, []);
useEffect(() => {
(async () => {
if (shouldWakeLock) {
await requestWakeLockSentinel();
return releaseWakeLockSentinel;
}
await releaseWakeLockSentinel();
})();
}, [shouldWakeLock, requestWakeLockSentinel, releaseWakeLockSentinel]);
return { isWakeLock: !!sentinel.current };
};
Reading an ebook
Presenting to an audience
Following a recipe
Map navigation
Scanning a QR / barcode
03
05
02
04
01
Provides information about the system's connection, such as the current bandwidth of the user's device or whether the connection is metered
Detect connection changes
import { useState, useEffect } from "react";
enum ENetworkEffectiveType {
SLOW_TWO_G = "slow-2g",
TWO_G = "2g",
THREE_G = "3g",
FOUR_G = "4g",
}
export const useNetwork = () => {
const [isFastNetwork, setIsFastNetwork] = useState<boolean | null>(null);
useEffect(() => {
if ("connection" in navigator) {
const { connection: { effectiveType } } = navigator;
setIsFastNetwork(effectiveType === ENetworkEffectiveType.FOUR_G);
}
}, []);
return isFastNetwork;
};
import { useState, useEffect } from "react";
enum ENetworkEffectiveType {
SLOW_TWO_G = "slow-2g",
TWO_G = "2g",
THREE_G = "3g",
FOUR_G = "4g",
}
export const useNetwork = () => {
const [isFastNetwork, setIsFastNetwork] = useState<boolean | null>(null);
const updateConnectionStatus = ({ target: { effectiveType } }: Event) => {
setIsFastNetwork(effectiveType === ENetworkEffectiveType.FOUR_G);
};
useEffect(() => {
if ("connection" in navigator) {
const { effectiveType } = navigator.connection;
setIsFastNetwork(effectiveType === ENetworkEffectiveType.FOUR_G);
navigator.connection.addEventListener("change", updateConnectionStatus);
}
}, []);
return isFastNetwork;
};
Notification to the user
Preload large resources
02
01
Provides a way to defer tasks to be run in a service worker until the user has a stable network connection
import React from "react";
import { Link } from "react-router-dom";
export const FlightsLink = () => {
const registerPlanetsSync = async () => {
const registration = await navigator.serviceWorker.ready;
try {
await registration.sync.register("sync-planets");
} catch {
console.log("Background Sync could not be registered!");
}
};
return (
<Link
to="rocket"
onMouseEnter={registerPlanetsSync}
>
EXPLORE
</Link>
)
}
import React from "react";
import { Link } from "react-router-dom";
export const FlightsLink = () => {
const registerPlanetsSync = async () => {
const registration = await navigator.serviceWorker.ready;
try {
await registration.sync.register("sync-planets");
} catch {
console.log("Background Sync could not be registered!");
}
};
return (
<Link
to="rocket"
onMouseEnter={registerPlanetsSync}
>
EXPLORE
</Link>
)
}
self.addEventListener("sync", (event) => {
if (event.tag === "sync-planets") {
event.waitUntil(fetchPlanets());
}
});
Offline capabilities
Send email while offline
02
01
import React from "react";
import { Link } from "react-router-dom";
export const FlightsLink = () => {
const registerPlanetsSync = async () => {
const registration = await navigator.serviceWorker.ready;
try {
await registration.sync.register("sync-planets");
} catch {
console.log("Background Sync could not be registered!");
}
};
return (
<Link
to="rocket"
onMouseEnter={registerPlanetsSync}
>
EXPLORE
</Link>
)
}
self.addEventListener("sync", (event) => {
if (event.tag === "sync-planets") {
event.waitUntil(fetchPlanets());
}
});
import React from "react";
import { Link } from "react-router-dom";
export const FlightsLink = () => {
const registerPlanetsSync = async () => {
const registration = await navigator.serviceWorker.ready;
try {
await registration.sync.register("sync-planets");
} catch {
console.log("Background Sync could not be registered!");
}
};
return (
<Link
to="rocket"
onMouseEnter={registerPlanetsSync}
>
EXPLORE
</Link>
)
}
const fetchPlanets = async () => {
const planetsResponse = await fetch(
"https://exoplanetarchive.ipac.caltech.edu"
);
const planets = await planetsResponse.json();
};
self.addEventListener("sync", (event) => {
if (event.tag === "sync-planets") {
event.waitUntil(fetchPlanets());
}
});
Allows basic communication between browsing contexts (that is, windows, tabs, frames, or iframes) and workers on the same origin
Bi-directional communication
import React from "react";
import { Link } from "react-router-dom";
export const FlightsLink = () => {
const registerPlanetsSync = async () => {
const registration = await navigator.serviceWorker.ready;
try {
await registration.sync.register("sync-planets");
} catch {
console.log("Background Sync could not be registered!");
}
};
return (
<Link
to="rocket"
onMouseEnter={registerPlanetsSync}
>
EXPLORE
</Link>
)
}
const fetchPlanets = async () => {
const planetsResponse = await fetch(
"https://exoplanetarchive.ipac.caltech.edu"
);
const planets = await planetsResponse.json();
};
self.addEventListener("sync", (event) => {
if (event.tag === "sync-planets") {
event.waitUntil(fetchPlanets());
}
});
import React from "react";
import { Link } from "react-router-dom";
export const FlightsLink = () => {
const registerPlanetsSync = async () => {
const registration = await navigator.serviceWorker.ready;
try {
await registration.sync.register("sync-planets");
} catch {
console.log("Background Sync could not be registered!");
}
};
return (
<Link
to="rocket"
onMouseEnter={registerPlanetsSync}
>
EXPLORE
</Link>
)
}
const broadcast = new BroadcastChannel("planets-channel");
const fetchPlanets = async () => {
const planetsResponse = await fetch(
"https://exoplanetarchive.ipac.caltech.edu"
);
const planets = await planetsResponse.json();
broadcast.postMessage({ planets });
};
self.addEventListener("sync", (event) => {
if (event.tag === "sync-planets") {
event.waitUntil(fetchPlanets());
}
});
import React from "react";
import { Link } from "react-router-dom";
export const FlightsLink = () => {
useEffect(() => {
const broadcast = new BroadcastChannel("planets-channel");
broadcast.onmessage = ({ data: { planets } }) => setPlanets(planets);
return () => broadcast.close();
}, []);
const registerPlanetsSync = async () => {
const registration = await navigator.serviceWorker.ready;
try {
await registration.sync.register("sync-planets");
} catch {
console.log("Background Sync could not be registered!");
}
};
return (
<Link
to="rocket"
onMouseEnter={registerPlanetsSync}
>
EXPLORE
</Link>
)
}
const broadcast = new BroadcastChannel("planets-channel");
const fetchPlanets = async () => {
const planets = await fetch(
"https://exoplanetarchive.ipac.caltech.edu"
).then((response) => response.json());
broadcast.postMessage({ planets });
};
self.addEventListener("sync", (event) => {
if (event.tag === "sync-planets") {
event.waitUntil(fetchPlanets());
}
});
Detect user action
Logout in all tabs
02
01
Beacon API
Web Speech API
Web Share API
Background Fetch API
Notification API
Network API
WebRTC
Web Authn
Non-existing browser support
Experimental browser support
Device support
03
02
01
Backwards compability
04
Standardized code
Standardized code
Standardized code
Smooth learning curve
Increase performance
03
05
02
04
01
Internet is consuming 21% of the electricity
check out carbon footprint
website traffic
energy intensity
data transfers
n.mitrovic@vegait.rs
You can find me at
Link to the slides
https://github.com/nmitrovic-vega/superpowers-web-api