Next.js: Issue with styled-jsx and componentDidMount...

Created on 22 Feb 2017  路  8Comments  路  Source: vercel/next.js

I setup a repo demo of the problem, so ignore the rest of this post.
https://github.com/iamjacks/wrong-width

I recreated my issue in an example gist that has 2 files...
https://gist.github.com/iamjacks/ac55d4bc1229c69015c47b1a88c8ccb9~~

The initial (server side) rendering will result in the correct width output for the inner div. However, when navigating to the other page and returning back to the home page, the width is incorrect. Also, why is my window resize event listener causing setState warnings in that same situation when navigating back to the home page and resizing the window?

Not sure if this is a bug/issue with Next, React, or if I'm doing something wrong. I ran into this problem when I began building a content slider carousel for a school project. Whenever I'd go back to my home page the slides were bigger than they previously were on the initial render.

Edit: I realize now the issue is related to styled-jsx. If I remove the inline style and place it in a global in <head> instead, my code gets the correct element width after client side rendering.

All 8 comments

About the warning with setState it's because of this line https://gist.github.com/iamjacks/ac55d4bc1229c69015c47b1a88c8ccb9#file-index-js-L23 and this one https://gist.github.com/iamjacks/ac55d4bc1229c69015c47b1a88c8ccb9#file-index-js-L27.

When you bind a function you are creating a new function, to remove an event listener you must pass the exactly same function, but you are binding the function two times and you are creating 2 different functions in memory, so it's not removing the listener.

@sergiodxa thank you sir! I took out the bounded functions from the event listeners and then assigned it in my constructor.

@iamjacks you can also use class properties to avoid doing the bind.

class YourComponent extends React.Component {
  eventHandler = () => {
    // your code here
  }

  componentDidMount() {
    window.addEventListener('event', this.eventHandler);
  }

  componentDidMount() {
    window.addEventListener('event', this.eventHandler);
  }

  render() { ... }
}

Next.js allow you to use class properties without any configuration. But yeah, binding in the constructor should fix your problem.

Edit: I realize now the issue is related to styled-jsx. If I remove the inline style and place it in a global in instead, my code gets the correct element width after client side rendering.

I believe this is because the code in componentDidMount is executed before styled-jsx when switching routes. And when server rendering the styles are precompiled when sent to the client. So it renders correctly when coming from the server because the styles are already there. cc @giuseppeg.

@iamjacks can you put together a repo that I can clone and try right away?

@nkzawa this is an issue with rAF. I believe that the issue is with styles updates being async and therefore the computed element width is wrong because it's not been affected by styles yet.

I tried to hardcode isSafari = true and the OP's code works as expected. cc @ericf

@giuseppeg makes sense. It seems the only solution is to remove the batch update :(

Was this page helpful?
0 / 5 - 0 ratings