ctrlplusb / react-sizeme Goto Github PK
View Code? Open in Web Editor NEWMake your React Components aware of their width and height!
License: MIT License
Make your React Components aware of their width and height!
License: MIT License
Hello,
Thanks for this product!
I have a component that I need to call a data refresh method on when it is unhidden from a view. Wrapping it in sizeme was great for helping it to size correctly, but now I can't access it to call the refresh because the object is now a resizeme thing, instead of the old component with the refresh function.
How can I send a message to the object inside sizeme?
Some much needed family quality time.
I'll be leaving the laptop at home.
I still care, I just won't be able to reply until the 26th.
x
its not working with redux, the reducers are not re-rendering the component
I'm using the default configuration and any actions that i trigger on the container are only presented to the screen after a window resize.
I've been using react-sizeme
to render an appropriate component based on the real estate available. One common pitfall with this use case is having your render switch out the root element completely.
For example:
class MySizedComponent extends Component {
render() {
const { size: { width } } = this.props;
return width > 500
? <WideComponent />
: <NarrowComponent />;
}
}
Don't do this.
If you do you may get issues with the ref handler that react-sizeme
uses to monitor your components dimensions with. Instead, always have a root element in your return that will never change.
For example:
class MySizedComponent extends Component {
render() {
const { size: { width } } = this.props;
return (
<div>
{
width > 500
? <WideComponent />
: <NarrowComponent />
}
</div>
);
}
}
Note the wrapping div
. Yes it's an extra DOM element, but it's semantically equivalent and now you get a nice dynamic component switcher outer.
Thought it worth sharing this. I'll add it to the docs, perhaps under the heading "common pitfalls".
react-sizeme
depends on element-resize-detector
and it currently fails minification with babili
due to an error I reported over there: wnr/element-resize-detector#71
This was a bit painful to track down because the code is obfuscated.
This is a production show-stopper for me; hoping for a quick resolution over there because I'm unfamiliar with browserify. If someone here is familiar with browserify, I would think it's a quick fix. Once fixed, we'll need a new release of react-sizeme
.
The behaviour of element-resize-detector causes a div to be injected which helps with tracking. Unfortunately this can break your flex layouts. To resolve you need to create a wrapping div around the flex layout div.
Not sure if the issue lies with the provider. May need to consider a stabler alternative.
This always ends up happening at some point when I resize the window, and it stops sizeMe from working until the page is refreshed.
Uncaught TypeError: Cannot read property 'width' of undefined
at finalizeDomMutation
at Object.process
at processBatch
Happens in
function finalizeDomMutation() {
debug("finalizeDomMutation invoked.");
if (!getState(element)) {
debug("Aborting because element has been uninstalled");
return;
}
var style = getState(element).style;
storeCurrentSize(element, style.width, style.height);
positionScrollbars(element, style.width, style.height);
}
Here is the result of getState(element)
:
So, yeah, style
isn't there. Is there something I'm doing wrong?
Add refreshDelayStrategy
config option, remove lodash dependency and recude a lib size.
import sizeMe from 'react-sizeme';
import debounce from 'debounce';
export default sizeMe({
refreshDelayStrategy: (work) => debounce(work, 16),
});
We have a lot of dependencies in our projects. If each lib reduce size by few kb... its ~30*4=120Kb...
It would be useful if we could access functions of the original component. It's an usual requirement, but it is a documented pattern.
I think the easiest way to achieve this is to make sure that the SizeMe
container has a ref
to the component passed into it. That way the parent of the SizeMe
wrapper can call this.refs.wrapped.refs.original.doSomething()
.
Hi,
Current implementation seems great. However often our wrapped component will often use width / height to define "breakpoints" from which the component should render differently according to its size.
A problem with current implementation is that it injects width/height directly to wrapped component, so each time the dimensions changes, the wrapped component will generally re-render because of a props change. If the wrapped component is expensive to render it can be a problem.
It would really help if we had a "mapDimensionsToProps" option for the HOC.
The default would be retrocompatible with current behavior:
const sizeMeConfig = {
monitorWidth: true,
monitorHeight: false,
refreshRate: 16,
mapDimensionsToProps: dimensions => dimensions
};
but it would be possible to customize props passed to our wrapped component. For example imagine I want my wrapped component to customize itself when it is a perfect square, I don't need it to re-render on every dimensions changes. Just injecting it a boolean "isSquare" should be enough and would allow to prevent unnecessary renderings easily with shouldComponentUpdate.
const sizeMeConfig = {
monitorWidth: true,
monitorHeight: false,
refreshRate: 16,
mapDimensionsToProps: ({width,height}) => {isSquare: (width === height)}
};
I'm using this on my code and it works great
https://gist.github.com/slorber/27006e27997464c9f737ac22a8a89a94
2.3.0 main entry (commonjs) imports full lodash
https://github.com/ctrlplusb/react-sizeme/blob/master/commonjs/sizeMe.js#L23
It should not wait to read the size from the DOM for the first render.
(Closing since I can't reproduce this when trying the same code on another machine.)
This component seems to insert a bunch of DIV elements around its children, and one of them is being explicitly styled to have a width and height of zero. Any children inside a component created with sizeMe() will disappear from the screen.
In a file "ScaleDiv.jsx":
import React, { Component } from 'react';
import sizeMe from 'react-sizeme';
class ScaleDiv extends Component {
render() {
return (
<div>{ this.props.children }</div>
);
}
}
const DecoratedScaleDiv = sizeMe({})(ScaleDiv);
export default DecoratedScaleDiv;
Then in a parent's render() method:
<ScaleDiv>HELLO</ScaleDiv>
"HELLO" disappears until I remove the call to sizeMe().
v2.4.1 is working without problem with SSR. v2.4.2 throws error window is undefined with SSR.
ReferenceError: window is not defined
at module.exports (/home/anon/Github/nextjs/mobx/node_modules/element-resize-detector/src/reporter.js:21:18)
at module.exports (/home/anon/Github/nextjs/mobx/node_modules/element-resize-detector/src/element-resize-detector.js:91:20)
at createResizeDetector (/home/anon/Github/nextjs/mobx/node_modules/react-sizeme/src/resizeDetector.js:9:27)
at resizeDetector (/home/anon/Github/nextjs/mobx/node_modules/react-sizeme/src/sizeMe.js:171:20)
at Object.sizeMe (/home/anon/Github/nextjs/mobx/.next/dist/bundles/pages/webpack:/pages/index.js?f7ee:51:22)
at __webpack_require__ (/home/anon/Github/nextjs/mobx/.next/dist/bundles/pages/webpack:/webpack/bootstrap 96d62891e60ba037ef65?3539:21:1)
at Object.2 (/home/anon/Github/nextjs/mobx/.next/dist/bundles/pages/index.js:2885:18)
at __webpack_require__ (/home/anon/Github/nextjs/mobx/.next/dist/bundles/pages/webpack:/webpack/bootstrap 96d62891e60ba037ef65?3539:21:1)
at /home/anon/Github/nextjs/mobx/.next/dist/bundles/pages/webpack:/webpack/bootstrap 96d62891e60ba037ef65?3539:68:1
at Object.<anonymous> (/home/anon/Github/nextjs/mobx/.next/dist/bundles/pages/index.js:73:10)
at Module._compile (module.js:649:30)
at Object.Module._extensions..js (module.js:660:10)
at Module.load (module.js:561:32)
at tryModuleLoad (module.js:501:12)
at Function.Module._load (module.js:493:3)
at Module.require (module.js:593:17)
errors is shown right after I wrap my component. first render goes with SSR. Previous version worked without problems.
First of all I want to say thanks for the great work, I love the idea! 👍
I thought to make similar thing, but found react-sizeme
could be a pretty good fit in my case..
The question is: why not to add the position tracking also?.. I'm working on drag'n'drop example in react-layer-stack and I what I need is to track the actual positions and sizes of "dropzones". What do you think?
Hi, I created an example here https://codesandbox.io/s/y0k255q7kx. I'm following the example of how to use onSize, but can't figure out why the text "header' isn't rendered when I pass onSize into HeaderWithSize. Can you take a look and point out what I'm missing?
Thanks!
I'm using this library for passing the width to child component like so.
<SizeMe>
{
({ size }) => (
<TemplateContent
file={selectedFile}
numPages={numPages}
pageNumber={pageNumber}
width={size.width}
/>
)
}
</SizeMe>
After re-sizing the dome for checking the responsive ness i'm getting this warnings a lot.
Warning: Can't call setState (or forceUpdate) on an unmounted component. This is a no-op, but it indicates a memory leak in your application. To fix, cancel all subscriptions and asynchronous tasks in the componentWillUnmount method.
in Form (at index.js:117)
in BuildLinkForm (at EmployeeNavbar.js:97)
in div (created by Modal)
in div (created by Modal)
in div (created by Modal)
in Modal (created by Modal__DefaultModal)
in Modal__DefaultModal (at index.js:74)
in Modal (at EmployeeNavbar.js:89)
in div (created by EmployeeNavbar__LinksItemContainer)
in EmployeeNavbar__LinksItemContainer (at EmployeeNavbar.js:88)
in div (created by Toolbar)
in Toolbar (created by EmployeeNavbar__ContentContainerForDesktop)
in EmployeeNavbar__ContentContainerForDesktop (at EmployeeNavbar.js:421)
Please let us know how to handle this.
So instead of just width and height we could pass along top, left, bottom and right.
Did you hear of this one yet? What do you think about it?
Hey it is me again with a feature request/proposal. I was positively surprised that react-sizeme comes with a refresh rate, as I need to debounce the re-rendering cause of heavy computations caused by some highcharts I use.
So I simply set the refreshRate to 300ms and it worked quite perfect for me. But than I figured out, that the first re-rendering after componentDidMount, which replaces the placeholder with the real content, took also 300ms to show up.
So it would be cool to decouple the Initial re-rendering from the refreshRate, to instantly show up the content when the componentDidMount().
What do you think. I would create a PR for that.
We use react-sizeme in a large application and resizeDetector stays in memory (it is a singleton). The result is that all react-sizeme children stay in memory and the retained memory from resizeDetector becomes larger and larger. We forked react-sizeme to create resizeDetector in the wrappedComponent so that resizeDetector is removed when the wrappedComponent is unmounted.
Do you have a reason to keep the resizeDetector as a singleton?
As I work in an enterprise portal environment I have to deliver my React bundles in a quite unorthodox way.
I attach the Webpack build bundle to the window object. The output
property of my Webpack config looks a little bit like this:
{
libraryTarget: 'var',
library: ['reactComponents', 'myStuff123']
}
I then pick up the component from the window object (e.g. window.reactComponents.myStuff123
) and render the React component as such:
ReactDOM.render(
React.createElement(window.reactComponents.myStuff123),
document.getElementById('UNIQUE_ID')
);
However, as I add a package, which includes react-resizeme, to the window object I guess that it's immediately trying to set up some event listeners or such, because I get this error:
Uncaught TypeError: Cannot read property 'insertBefore' of null
Is there any way of postponing the execution until it's actually rendered?
A full example of the HTML and loading mechanisms looks like this:
<!DOCTYPE html>
<html>
<head>
<script src="react-0.14.8.min.js"></script>
<script src="react-dom-0.14.8.min.js"></script>
<script src="bundle.js"></script>
</head>
<body>
<div id="UNIQUE_ID"></div>
<script>
(function(){
ReactDOM.render(
React.createElement(window.reactComponents.NamespacedReactComponent),
document.getElementById('UNIQUE_ID')
);
})();
</script>
</body>
</html>
I have been attempting to implement support for SSR. So far, the only semi-working solution I could come up with involves avoiding calling createResizeDetector
if the window object is undefined.
My fork is here lyuzashi@1242009
Doing so will prevent any errors, however components that are wrapped by SizeMe are not included in the server-side rendered HTML.
This appears to be due in part to the RenderWrapper, which is helpfully commented to be treaded on lightly.
By setting the initial state of both width and height in SizeAwareComponent to NaN, the wrapper is short circuited and the component renders without error on both the server and client.
This approach, however, does not pass the included tests – specifically any time the placeholder is expected to render before a size change occurs.
Other attempts at cracking this puzzle have caused checksum errors.
I am not entirely sure what the placeholder does. I'm fairly new to React but I get the feeling it's pretty important not to short-circuit it.
Any help would be greatly appreciated. I'd love to get SSR working with this component – it looks very handy! Sorry this is so detailed.
As a note, I chose to try NaN as the size for SSR, since it theoretically is a dimensionless environment but existing math code wont error out or evaluate in unexpected ways (due to casting), as it might with null. Not sure if that's the best idea, but it's what I came up with as a suggestion.
HI ,
I am using 2.4.2 version and getting following two errors
there is one similar issue was already logged,but its status is closed.
So logging it again.
I was wondering whether the size of this lib, as reported in the readme, is still correct. For me, when only minified, this lib adds 148kB (when bundled separately, with webpack).
When testing the gzip compression with https://closure-compiler.appspot.com/home, I get the following gzip size:
Original Size:
44.6KB gzipped (144.64KB uncompressed)
Compiled Size:
39.17KB gzipped (108.37KB uncompressed)
Saved 12.17% off the gzipped size (25.08% without gzip)
So it compresses down to roughly 45kB gzipped. Now I'm assuming that the difference isn't just webpack bundling overhead. Do you know why my results are so different from the 9kB from the readme, am I overlooking something?
I would like to set my layout component height Content
= windows height
<Content style={{minHeight: .....}}>
</Content>
Please help me.
Would it be more intuitive this way?
I was having trouble wondering why my size.height does not get updated only to figure out it is not monitored by default.
Thanks for this package.
Hey, I tested your library and it works pretty good so far. Anyhow I get the following error on initialization:
sizeme-example.js:691 Warning: Failed propType: Required prop
size.width
was not specified inSizeMeRender
. Check the render method ofSizeAwareComponent
I checked the code and you set
SizeMeRender.propTypes = {
...
size: PropTypes.shape({
width: PropTypes.number.isRequired,
height: PropTypes.number.isRequired,
})
};
but width and height are undefined in the first runs (which is pretty much the intended functionality).
Wouldn't it be better to change it to:
SizeMeRender.propTypes = {
...
size: PropTypes.shape({
width: PropTypes.number,
height: PropTypes.number,
}).isRequired
};
This way you enforce the shape, but allow the props inside of the shape to be undefined?
I was trying to use react-sizeme in my project and it didn't work.
So I tried setting up a basic working sandbox, and it doesn't work either.
What am I missing?
When using the react-component-queries package I get the following error. The package works as expected but I'm getting an error I'd rather not have in my console.
If you look at the screenshot below, you can see that the Container element (which I'm assuming is the placeholder you use) doesn't have any children.
I only use the component query on the top level component. I've tried wrapping the component in another component and a few other things but to no avail. The only problem I can think of is that I'm using preact with React aliased to preact-compat.
If the isUnrendered function isn't necessary to the functionality of react-sizeMe, I'd like to make a PR adding a check for undefined before line 183 and console log a warning so others can know what's going wrong?
Hello, thanks for your awesome work!
I cannot make sizeme
work with flex positioning. I'm tracking width and the size is updated only if component gets wider. If it becomes narrower, size does not change.
Hi! It seems like wrapping a div in sizeMeHOC
causes the outermost div to have a style: position='relative
attribute to be attached. This conflicts in cases where we set the position via a class on the outermost div.
Here is a "pseudo" reproduction:
class Foo extends Component {
render() {
return <div className="absolute" />
}
}
export default sizeMeHOC()(Foo);
Hey Sean,
Thanks a lot for your component – it saved me a couple of hours of life :–)
Not sure you would want to take this on board, but here is a thought that came to me when I was using Mapbox GL wrapped into react-sizeme
. There was an issue when my container div shrunk to 0 – WebGL immediately threw a nasty error because the viewport had to be at least 1 px in size. Here is my workaround for this:
// MySuperMap = ...
// Do not allow width / height be 0
const sizeMeFix = (ComponentToWrap) => ({ size, ...rest }) => {
const {
width,
height,
} = size || {};
const fixedSize = {
width: isNumber(width) ? Math.max(width, 1) : width,
height: isNumber(height) ? Math.max(height, 1) : height,
};
return <ComponentToWrap {...rest} size={fixedSize} />;
};
const MySizedSuperMap = sizeMe({
monitorHeight: true,
refreshRate: 200,
})(sizeMeFix(MySuperMap));
export default connect(mapStateToProps, mapDispatchToProps)(MySizedSuperMap);
So sizeMe
is a wrapper for another wrapper called sizeMeFix
, which makes sure that the wrapped component does not get incorrect numbers. I know I can fix the size right in the render()
method of my component, but the size might be requested in a few other methods and this will create unwanted repetitions.
There might be other cases when reported width and height need to be clamped, so maybe having extra options like reportedMinWidth
, reportedMaxWidth
, reportedMinHeight
, reportedMaxHeight
can be a useful addition to your wrapper:
const MySizedSuperMap = sizeMe({
monitorHeight: true,
refreshRate: 200,
reportedMinHeight: 1,
reportedMinWidth: 1,
})(MySuperMap);
What do you think?
The observer stops working when component content is replaced. This may be an issue especially with simple (e.g. text only) components.
My component looks like:
render(): JSX.Element {
return (
<div className="ellipsis">{this.state.truncatedText}</div>
);
}
When state changes it will replace text and also remove .erd_scroll_detection_container
element. There s error message and it makes it quite hard to debug. Simple solution is to wrap this.state.truncatedText in one more element e.g:
render(): JSX.Element {
return (
<div className="ellipsis" ref="container">
<span>{this.state.truncatedText}</span>
</div>
);
}
I believe it's worth to add info about DOM modyfication in the readme.
Have you ever considered having sizeMe work where you use a <SizeMe>
component and it passes the size down as a prop? I think this method feels a bit more readable. ReactMotion does something like this.
<SizeMe monitorHeight>
{size => <div>{size.width}, {size.height}</div>}
</SizeMe>
I am using the react-sizeme library to size my component like this:
import * as React from 'react';
import { connect } from 'react-redux';
import { compose } from 'redux';
import { withSize, Size } from 'react-sizeme';
class MyComponent extends React.Component<MyProps>{
render(){
return <svg
width="100%"
height="100%"
viewBox={`${-(this.props.size.width as number) / 2} ${-(this.props.size.height as number) / 2} ${this.props.size.width} ${this.props.size.height}`}
xmlns="http://www.w3.org/2000/svg"/>
}
}
export default compose(
withSize({ monitorHeight: true }),
connect(mapStateToProps)
)(MyComponent);
It is working fine, except for the fact that the component is not rerendered when I resize the window. Any help would be greatly appreciated.
In kibana 6.2.2, I'm getting:
optmzr log [16:47:31.933] [fatal][optimize] Optimization failed in 2.09 secondsError: Optimizations failure.
4192 modules
ERROR in ./node_modules/react-sizeme/dist/react-sizeme.js
Module not found: Error: Can't resolve 'lodash/debounce' in '/home/joey/Dev/sonark/node_modules/react-sizeme/dist'
ERROR in ./node_modules/react-sizeme/dist/react-sizeme.js
Module not found: Error: Can't resolve 'lodash/throttle' in '/home/joey/Dev/sonark/node_modules/react-sizeme/dist'
This was fixed if I went inside ./node_modules/react-sizeme/dist/react-sizeme.js and change the import of "lodash/debounce" and "lodash/throttle" to "lodash.debounce" and "lodash.throttle", respectively.
I'm getting the following exception in the issue fully described here (i can add details on request):
https://stackoverflow.com/questions/51408036/failed-to-execute-removechild-on-node-exception
scroll.js:639 Uncaught DOMException: Failed to execute 'removeChild' on 'Node': The node to be removed is not a child of this node.
at Object.uninstall (webpack:///./node_modules/element-resize-detector/src/detection-strategy/scroll.js?:639:36)
at eval (webpack:///./node_modules/element-resize-detector/src/element-resize-detector.js?:300:31)
at utils.forEach (webpack:///./node_modules/element-resize-detector/src/collection-utils.js?:14:22)
at Object.uninstall (webpack:///./node_modules/element-resize-detector/src/element-resize-detector.js?:298:9)
at SizeAwareComponent.componentWillUnmount (webpack:///./node_modules/pnk-react-components/node_modules/react-sizeme/dist/react-sizeme.js?:371:27)
at callComponentWillUnmountWithTimer (webpack:///./node_modules/react-dom/cjs/react-dom.development.js?:9687:14)
at HTMLUnknownElement.callCallback (webpack:///./node_modules/react-dom/cjs/react-dom.development.js?:104:14)
at Object.invokeGuardedCallbackDev (webpack:///./node_modules/react-dom/cjs/react-dom.development.js?:142:16)
at invokeGuardedCallback (webpack:///./node_modules/react-dom/cjs/react-dom.development.js?:191:29)
at safelyCallComponentWillUnmount (webpack:///./node_modules/react-dom/cjs/react-dom.development.js?:9694:7)
It should be possible to track inner width and height.
The title says it all. The position properties are only refreshed when the element itself is resized, causing the position to go stale any time the window resizes.
I was originally trying to use react-component-queries but I noticed that my queries were only ever run once on first render, after then trying to implement my own version of it using shouldComponentUpdate and react-sizeme I ran into this issue which seems to be the root of my original problem. I'm not that good with Chrome Devtools but it seems that when strategisedSetState is called that is also somehow bypassing shouldComponentUpdate and mutating the props object. I have noPlaceholder set to true as we are using SSR, but apart from that am not doing anything out of the ordinary.
Any help with this would be appreciated.
Could there be any typescript definitions?
Right now I made the following in my own code to create them, but it would be cool if they were on the package:
type Omit<T, K> = Pick<T, Exclude<keyof T, K>>;
export interface SizeMeProps {
size: {
width: number | null;
height: number | null;
};
}
export interface SizeMeOptions {
monitorWidth?: boolean;
monitorHeight?: boolean;
monitorPosition?: boolean;
refreshRate?: number;
refreshMode?: 'throttle' | 'debounce';
noPlaceholder?: boolean;
}
type SizeMeFunction = (options?: SizeMeOptions) => <P extends SizeMeProps>(component: React.ComponentType<P>) => React.ComponentType<Omit<P, 'size'>>;
export const sizeMe: SizeMeFunction = require('react-sizeme');
error "react-sizeme#react@^0.14.0 || ^15.0.0-0" doesn't satisfy found match of "[email protected]"
When I try to use react-sizeme
, it shows this warning in my console.
Warning: Accessing PropTypes via the main React package is deprecated. Use the prop-types package from npm instead.
So how can I fix it?
Here the code I implement.
class CassettePlayer extends Component {
}
import sizeMe from 'react-sizeme';
export default sizeMe()(CassettePlayer);
Can you add support for debounce as an alternative to throttling? This can be useful for a smoother resize experience and reduced recalculation thrashing.
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.