babel-plugin-styled-components icon indicating copy to clipboard operation
babel-plugin-styled-components copied to clipboard

🐞 react-responsive ssr produces collision in generated classes names

Open jperelli opened this issue 3 years ago • 0 comments

When using https://github.com/contra/react-responsive in next.js server side generated page (getServerSideProps), some components get the className wrong

this is the code (reduced for simplicity)

          <MediaQuery minDeviceWidth={resolutions.MIN_LG_SIZE}>
            <Row>
              something here
            </Row>
          </MediaQuery>
          <MediaQuery maxDeviceWidth={resolutions.MAX_MD_SIZE}>
            <Row>
              another thing here
            </Row>
            <Row style={{ marginBottom: '10px' }}>
             yadda yadda
            </Row>
          </MediaQuery>
          <Row>
            <Col>
              <ExperienceDates>
                this is a styled component text
              </ExperienceDates>
            </Col>
          </Row>
          <Row style={{ marginTop: '25px' }}>
            <Col sm={24}>
              <Description>
                another styled component, THIS HAS THE CLASS OF THE NEXT ONE, (Subtitle)
              </Description>
            </Col>
          </Row>
          <Row style={{ marginTop: '4px' }}>
            <Col sm={24}>
              <Subtitle>
                another styled component
              </Subtitle>
            </Col>
          </Row>

image

Description and Subtitle components are like this

export const Description = styled.p`
   ...css...
`

export const Subtitle = styled.p`
   ...a different css...
`

If I change the styled.p for a styled.span in one of them, the issue goes away.

I was a week trying to figure out what was happening, changing all sorts of configuration to no avail.

The I figured this might have something to do with <MediaQuery /> mounting/unmounting the child components and it messing around with the indices (or keys) of the internal <Row />s or styled.ps, so I tried reimplementing <MediaQuery /> to just being a styled component that applies display: none with a media query (no mount/unmount), like this

export const MediaQuery = styled.div<{ minDeviceWidth?: number; maxDeviceWidth?: number }>`
  @media (max-width: ${(props) => props.minDeviceWidth}px) {
    display: none;
  }
  @media (min-width: ${(props) => props.maxDeviceWidth}px) {
    display: none;
  }
`

And it worked!!

The only issue is that with this implementation, all the ui (for laptop+mobile) is rendered in jsx but only is hidden with display: none, it's a no-go for performance.

jperelli avatar Jul 23 '20 09:07 jperelli