Legitcode / image

an img tag, with lazy loading
http://legitcode.github.io/image/
47 stars 0 forks source link

Server-side pre-rendered images stuck at opacity: 0 #4

Closed austinpray closed 8 years ago

austinpray commented 9 years ago

When using the react-redux-universal-hot-example repo as a starting point (https://github.com/erikras/react-redux-universal-hot-example/tree/4705688b879f853ede08e3872bc083cc84227824)

My component:

<Image className="thumbnail" src="https://i.imgur.com/l50kGUz.png" />

The HTML that comes through in the view source:

<img class="thumbnail" src="https://images.unsplash.com/photo-1439003511744-2a0490ea0a88?q=80&amp;fm=jpg&amp;s=4dd5809698048edf8b82eedb82ca8cec" style="transition:opacity 1s;opacity:0;" data-reactid=".mzv5v08jcw.2.0.0.0">

Notice how the opacity is frozen at 0.

How to reproduce:

  1. Clone that example repo down
  2. npm i --save legit-image
  3. Spam Image tags on the homepage or whatever page
  4. npm start

Race condition with server-side rendering?

zackify commented 9 years ago

Well it's stuck at opacity 0 because when it is initially rendered the opacity is supposed to be 0. I'm assuming you didn't mount the component on the client side after server rendering? I'm trying to think of a way to make this work correctly when you only want to server render...

zackify commented 9 years ago

The only fix I can think of is that you have to include the component client side, and if server rendering pass a prop, something like server={true} so that it will just return a regular image tag if it's server rendered

austinpray commented 9 years ago

I'll see if I can come back with a solution after looking at your code. Haven't peeped it yet.

zackify commented 9 years ago

It's really simple, I completely see the problem, just unsure of the easiest way to fix it.

constb commented 8 years ago

@zackify how about rendering it with data-src, loading image client side with new Image and then setting src and triggering transition? I think the root cause of this problem is that with server-rendered img tag image gets loaded before component is mounted and thus it doesn't receive load event.

constb commented 8 years ago

@zackify also this way it would be easy to implement #3

constb commented 8 years ago

@zackify actually, now that I thought about it, maybe you don't need src or data-src on initial render. After all you aren't exposing image url to any outside code. You can manually preload image and then set src only when it's already in the browser cache.

zackify commented 8 years ago

@constb so what would be the real fix for this?

austinpray commented 8 years ago

@zackify he's talking about a solution like this:

https://github.com/Flipboard/react-canvas/blob/0148605a654a8560a5bd8e9740579b719fec1b38/lib/ImageCache.js

https://github.com/Flipboard/react-canvas/blob/0148605a654a8560a5bd8e9740579b719fec1b38/lib/Image.js#L53

constb commented 8 years ago

ah, I see the ambiguity here. by new Image() I meant new window.Image() of course. It has its own onload and onerror, and setting src on it triggers request without affecting the DOM. After it's loaded you just set DOM's img.src to the loaded Image's src and start the transition. Changing props.src should work the same way.

zackify commented 8 years ago

@austinpray @constb sorry about it being 6 months later... I think I came up with an easy solution. If window is undefined, it will return opacity: 1. Even if you have React mount client side, you probably want images to show before it renders there.