souporserious / react-measure

📏 Compute measurements of a React component.
https://souporserious.github.io/react-measure/
MIT License
1.94k stars 109 forks source link

Getting a flash of 0 width after updating to v2 #53

Open tnrich opened 7 years ago

tnrich commented 7 years ago

Hey there,

I recently made the switch to v2 of react-measure and now seem to get a flash of 0 width when rendering my component whereas before things just worked smoothly (no flash).

In my case I'm using react-measure to set the column widths of a datatable:

Here is the flash: asdfasdfasd

Any ideas why it might be happening with the new api but not the old one?

Thanks!

tnrich commented 7 years ago

Just to add some more info, here is the same page reload after reverting back to react-measure ^1.4.7

asdfasdfasd

Here is my git diff for my component:

diff --git a/src/DataTable/index.js b/src/DataTable/index.js
index a4942af..4e4e807 100644
--- a/src/DataTable/index.js
+++ b/src/DataTable/index.js
@@ -169,51 +169,44 @@ class DataTable extends React.Component {
         </div>
         <div className={"data-table-body"}>
           <Measure
-            bounds
-            onResize={contentRect => {
-              this.setState({ dimensions: contentRect.bounds });
-            }}
+                      onMeasure={dimensions => {
+                        this.setState({ dimensions });
+                      }}
           >
-            {({ measureRef }) => {
-              return (
-                <div ref={measureRef}>
-                  <Table
-                    numRows={numRows}
-                    columnWidths={columnWidths}
-                  >
-                    {entities && this.renderColumns()}
-                  </Table>
-                </div>
-              );
-            }}
+            <Table
+              numRows={numRows}
+              columnWidths={columnWidths}
+            >
+              {entities && this.renderColumns()}
+            </Table>
           </Measure>
         </div>
         {!isInfinite &&
souporserious commented 7 years ago

Interesting! Sorry about that. I will look into this as soon as I get a chance. Wondering if it has to do with the removal of findDOMNode 🤔

robwise commented 7 years ago

I can confirm I'm getting this too

souporserious commented 7 years ago

@robwise how are you using the component? Can you provide a small test case as well if possible? I haven't been seeing this yet and haven't had time to dig in 😞 hoping to look this week

robwise commented 7 years ago

Does this link work? I made a trivial example where the background is green if the detected width is greater than 0, blue otherwise. Since the width is always greater than 0, it should never be blue, always green. I made a long transition so you can see it better.

https://codesandbox.io/s/nZy0XkrZE

souporserious commented 7 years ago

Thank you! I appreciate it. I think that's to be expected, and I believe might have been hidden on accident with the previous version, possibly because of findDOMNode. Since the node needs to to mount before it can be measured, you can use the natural width/height until you have a measurement and then apply it. This should get rid of any flickering. I'll try and put together a small demo tomorrow to test that and make sure it works like I think it should. I'll also make some notes on the README after we figure this out.

robwise commented 7 years ago

Roger that, yeah because that example I gave is trivial so that it was clear what was going on, but in my own app I'm actually using react-measure to determine the width of a certain element so I know what responsive image to retrieve from Cloudinary. The flicker, therefore, causes a 404 when I request the wrong size so it's very troublesome.

souporserious commented 7 years ago

Oh no 😕 that sounds nasty. It sounds bigger than what I'm thinking. If you happen to find any more info, please let me know. I'll look into this ASAP.

robwise commented 7 years ago

@souporserious Do you have an example of "using the natural width/height"? I'm not sure how to do this

adrienharnay commented 7 years ago

Hi, stumbled on this too. Before the update, onMeasure (now onResize) was called after the first render, with the right bounds. Now it is called after, and this causes a flash as @robwise pointed out.

It is also not clear to me how to use natural width/height whilst waiting for first render...

souporserious commented 7 years ago

@robwise sorry, that was pretty vague. I meant using the "auto" values until they have been calculated. So something like contentRect.bounds.width || 'auto'. I'm going to revisit all of this soon and try to ease all the pain and bugs coming from 1.0 to 2.0. I think I have a good grasp of the pain points and can hopefully get the same benefits from 1.0 plus more in a 2.1 version.

robwise commented 7 years ago

Ohh okay gotchya. Appreciate that I'm looking forward to it! Let me know if there's something you need me to help with

themre commented 6 years ago

Confirm, this problems doesn't occur with 1.x, but happens with 2.x.

colinhunt commented 6 years ago

Hi, any updates on this? I'm trying to use react measure to position an element, so I need the correct location right away, or else the element is rendered in the wrong spot initially and then jumps into place. Sounds like I would currently need to detect if the dimensions are 0 and hide the element until it has been measured properly...

souporserious commented 6 years ago

Sorry it has taken a while to get to this. I'm currently working on v3. I'll try and get a beta published soon so you can try it out. It should fix this issue as well as other current issues filed for this library.

colinhunt commented 6 years ago

Hey no worries, thanks for the extremely useful library and all your hard work! My workaround was easy to implement and appears to be working. In render(), I just set visibility: hidden if the dimension I'm interested in is 0, and also allows it to be re-measured with the proper dimensions. Then when onResize() is called, I do

      this._dimensions = dimensions;
      this.forceUpdate(); // to cause rerender with updated dimensions

and use this._dimensions in the render method.

souporserious commented 6 years ago

Nice! Yeah, you shouldn't have to do that in the latest version 🤞. I realized that a ResizeObserver's first call takes too long which I'm pretty sure is why it flashes when trying to use dimensions on first mount.