I’m creating a lightbox image gallery using React. On the lightbox, which pops and displays the image, I’m minimizing images so they could fit properly on the screen. I created an image resize function to fit a large image onto the screen, which I set the image width and height state as it’s value.
When I use console.log(this.imageResize(width, height).width), it’s correct whenever I click both the left and right arrows to navigate to the next/previous images. But when I pass the jsx image element’s width’s value as the image width’s state, it’s a different result as if the previous state looks to be a problem here.
From looking at your code it should actually set the state correctly; however state updates are happening ansynchronously… it does not alter the state right away, but just tells react to update when appropriate – see here for an in depth explanation. Hence, if you immediately log the state you’ll still get the old one; but you can pass a callback that gets called after the state got actually updated:
BTW, it’s very inefficient to declare your Arrow components anew each time inside the render function… better put these next to the Thumbnail component (or even in a dedicated module).
Thanks for helping me out. I’ve been trying to solve this issue for days. As you’ve said, the setState behaves asynchronously. Which could be why the width will return undefined after a couple of state changes. Unfortunately, the callback doesn’t seem to help solve the issue, either it seems. Maybe there need to be some kind of logic to reset the state in the callback after it’s update? Or would there be another way to solve this?
I’m going to refactor my code and also move the Arrow Components outside of the render function and into a separate file for better inefficiency. Thanks for pointing that out.
I found another issue with your code; in the imageResize() method, you sometimes return an object, sometimes a number primitive. Also, are you sure you want to take the target.width and target.height as a basis for your calculations? These would refer to the width and height attributes of the image, which are the attributes you are actually trying to set… what you want is probably the target.naturalWidth and target.naturalHeight properties, respectively. I put together a simplified version of your component with just the relevant bits that seems to be doing what you want:
But then again, why use JS for this in the first place… couldn’t you simply set a max-width: 80vw or something in the CSS? Otherwise you’d also have to listen to browser resize and orientationchange events, not to mention the additional overhead…
The images didn’t display properly in css at first, so I decided to write it in JavaScript instead. I knew if I got the imageSize() and state changes working properly, I would have to create a handler for a resize event. You’re definitely right about that.
I always preferred to implement something like this in css, but I never used vw/vh type values. I didn’t know much about them. I thought it was only used for font sizing based on the viewport’s width and height. I tried it out and it works perfectly! For days, I couldn’t figure this issue and now it’s solved. I should’ve post this question on the same day or the next day that I was having issues with this code. I shouldn’t have waited so long
Thanks for taking the time in writing your code. I’m going to look at it so I could improve my skills to be better.
Thanks for the other tips! May I ask, why is it appropriate to not create any functional stateless components in the render function? I’m assuming it has a lot to do with performance and other unexpected behaviors. Is there a article out there you can link me to? I always want to be a better React Developer and it’s been a while since anyone reviewed my code.
Edit: Now I see why it’s very important not to create any functional components in the render function. When I place the functional stateless components outside of the render function, it doesn’t cause any unnecessary re-render whenever the state changes.