rob2d / use-viewport-sizes Goto Github PK
View Code? Open in Web Editor NEWtiny React hook which allows you to track visible window viewport size in your components w/ an optional debounce for updates for optimal rendering.
License: MIT License
tiny React hook which allows you to track visible window viewport size in your components w/ an optional debounce for updates for optimal rendering.
License: MIT License
when using viewport sizes library, the implementation itself is pretty optimal for what it does. But there are some cases where we may want to prevent re-rendering or updating of returned value unless the viewport meets some criteria. This would then let React go without passing through subsequent hooks which need to check for a diff; e.g. useMemo. While it's not necessarily expensive, the browser is already doing a lot of work internally to reflow CSS.
Another very common use case would be for emulating media viewports e.g. max width or min width. Since React would not know the difference on a media query without passing a callback, this library can also be a really nice fill in replacement with much less overhead (which in large part it is meant for). This would also decrease the stutter or jankness when resizing some screens and when it's only relevant in certain breakpoints (for example when using Material UI @ material-ui.com breakpoints).
Currently considering to do this via a passed in callback function (not a hook), with a return value that is observed (e.g. internally via useMemo) that can detect change triggers to return new values. This way from the outside calling hook fn/component, it may or may not update.
Example usage as follows:
(callback declared once above fn component)
/**
* when callback returns 'sm' or 'md', render one time
*/
const getVpBreakpoint= ({ vpW, vpH }) => {
return vpW < 200 ? 'sm' : 'md';
};
(within component)
/**
* will only recompute and return sizes when the observer
* function changes; this ensures things do not re-render,
* and the additional memorized property is available as
* the third param now.
*
* the main convenience is that the callback is ran on
*every viewport change, but the component is not forced
* to re-render! So this is much less boilerplate than
* observing via callbacks.
*/
const [vpW, vpH, vpBreakpoint] = useVpSizes(shouldUpdateVpSizes);
I looked through the source code and noticed that the window
variable was global, so I was uncertain of how this would work with SSR. I setup up a codesandbox with NextJS and my assumptions were true: this fails in SSR as window
is only defined client side.
I tried calling the cmponent when the parent component is mounted, but didn't work.
Here's what I tried: https://codesandbox.io/s/wnnx49708
I don't know what would be the consecuences of declaring window inside a useEffect
to ensure the window
variable exists, as useEffect
is only called by the Client-side of the app.
I will be open for comment and sicussion, and maybe help, to add SSR suppport to this cool hook.
To replicate this bug, please follow these steps with the code sandbox:
Note: This codesandbox is just a basic flexible layout with CSS styles, media queries and basic react components and the bug happens within the Middle.js component.
Code: https://codesandbox.io/s/young-dawn-1x6jx?file=/src/App.js
Steps:
1.) Refresh the page - (The left yellow and right purple sides will randomly disappear after page refresh)
2.) Refresh the page again - (The left yellow and right purple sides will not come back)
3.) Adjust the size of the viewport - (The left yellow and right purple sides will randomly come back)
4.) Remove lines 3,5,6 from file: Middle.js - (The bug stops and it works normally)
What's wrong?: The left yellow and right purple sides should not disappear on refresh.
I have really no idea what's going wrong technically, but I think that this library is conflicting with the media queries or material-ui.
For the next release, will be providing a new interface which will be preferred over the previous parameter overloading. Example usage:
// default behavior
const [vpW, vpH] = useViewportSizes({ dimension: 'both' });
// with only one dimension observed, and `debounceTimeout` of `20` ms applied
const vpW = useViewportSizes({ dimension: 'w', debounceTimeout: 20 });
Input-option type:
export type VPSizesHasher = (({ vpW: number, vpH: number }) => String);
export type VPSizesOptions ={
debounceTimeout?: number,
throttleTimeout?: number,
hasher?: VPSizesHasher,
dimension?: 'w'|'h'|'both' = 'both'
};
The interface will be backwards-compatible, but the default behavior for numbers as input will be to throttle eventually vs debounce as a more natural resize method.
Initially will just default to debounceTimeout
behavior, but as a heads up to anyone using the library where it is going and why there may be a major semver version bump.
(input is welcome for anyone interested)
Would be great to get typescript inferences -- especially with upcoming throttle interface.
Probably best to go the route of typescript declaration file.
Hey, I love this hook, it does just the one thing it's supposed to!
I'd love to throttle the function rather than debounce, would be cool to see the changes while resizing. Now it requires the user to stop.
Would you be willing to put that in if I'd open a PR?
Interface is just about done after a bit more testing. In order to post meaningful documentation, there should be newer examples on Codebase. Would not hurt to make them look a lot nicer.
One idea particularly is to render the viewport sizes themselves on observed changes on CodeSandbox in addition to filled colorings (less-busy looking). Obviously could not do this in both directions at once, but the new dimension
option allows the examples to make more sense with component widths/heights changing themselves according to when updates are registered now.
Hey, first off, thanks for this really nifty hook, in particular the focus on performance and avoiding unnecessary re-renders!
I've been using it in a Vite project, and noticed I'm getting a warning during SSR b/c of useLayoutEffect
Warning: useLayoutEffect does nothing on the server, because its effect cannot be encoded into the server renderer's output format. This will lead to a mismatch between the initial, non-hydrated UI and the intended UI. To avoid this, useLayoutEffect should only be used in components that render exclusively on the client. See https://reactjs.org/link/uselayouteffect-ssr for common fixes.
This warning can be avoided by explicitly using useEffect
instead of useLayoutEffect
during SSR. Here's one really simple implementation:
https://usehooks-ts.com/react-hook/use-isomorphic-layout-effect
There's no change in behavior (both hooks are skipped during SSR). It's just a way of telling the framework that you know that this won't run on the server and are ok with that.
You cannot call useViewportSizes with no parameters, you get a compilation error.
Further, you cannot get properly typed parameters when you want only width and height, ignoring the triggerResize value. TypeScript assumes you're expecting the other result type which is dimension, triggerResize. Note, using the following causes eslint issues when you really don't want triggerResize and don't use it in subsequent source.
const [vpW, vpH, updateVpSizes] = useViewportSizes(); doSomething(vpW, vpH); // ignore updateVpSizes return; // Error will result because updateVpSizes is unused
Interface is just about done after a bit more testing, but need to rewrite the README.md
to annotate these changes before a major push to NPM.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.