Gatsby: React Slick breaks in Gatsby Build

Created on 23 Apr 2019  路  8Comments  路  Source: gatsbyjs/gatsby

WRT #8188 and #8184. Both these issues are pointing to similar behavior but were closed due to lack of info.

Issue:
Slick-carousel component works fine when running in the gatsby develop mode. But when we switch to the prod build using 'gatsby build', Slick-carousel behaves erroneously. The carousel is not able to scroll through all slides even with infinite scrolling enabled. On some digging around, we noticed irregular DOM attributes in the generated slick-carousel DOM.

The issue only occurs when we use the 'responsive' setting in the carousel to set different settings for different form factors.

A working sample of slick-carousel showcasing the minimal settings needed to repro the issue.

https://codesandbox.io/s/4j371vo8q4

The behavior in this sample is the expected one and matches the output from gatsby develop mode. The expectation is to show a carousel till 767px and to show all the slides when screen width is greater than 767px.

Prod Build Scenarios worth noticing:

  1. Open the URL in a browser at maximum width and then later on decrease browser window width to hit the breakpoint. The carousel works fine in this case. Observe the 'data-index' attribute on the slick slides. They appear in a sequence as expected.
    https://www.loom.com/share/8a72a50dbbb944008372cd62b5231c29
  1. Open the URL in a browser with screen width already below 768px. The carousel functionality breaks. The last 2 slides are duplicated. Observe the 'data-index' attribute on the slick slides. They have a duplicate entry at index 2.
    https://www.loom.com/share/35f88ad309b94e33aaffcfb371fcba75

Since the issue only comes while running the prod build, we suspect the internal gatsby procedures are somewhere causing a conflict with the slick-carousel code leading to the erroneous behavior. Please let us know how we can help in debugging this and getting it fixed pronto!

System Info:
Gatsby: 2.3.13
Node: 10.13.0
OS: Microsoft Windows [Version 10.0.17134.648]
Browser: Chrome

gatsby-config.js
module.exports = { plugins: [ 'gatsby-reporter-nva', { resolve: 'gatsby-plugin-robots-txt', options: { policy: [{ userAgent: '*', allow: '/' }], query:{
site: nvaSite {
siteMetadata {
siteUrl
}
}
} } }, { resolve:gatsby-source-contentful, options: getContentFulOptions() }, { resolve:gatsby-plugin-typography, options: { pathToConfigModule:src/utils/typography.js } }, { resolve: 'gatsby-plugin-react-svg', options: { rule: { include: /static/ } } }, { resolve: 'gatsby-plugin-root-import', options: { themes: path.join(__dirname, 'src/themes'), components: path.join(__dirname, 'src/components'), layouts: path.join(__dirname, 'src/layouts'), images: path.join(__dirname, 'src/static/images') } }, { resolve:gatsby-plugin-styled-components, options: { displayName: false } }, gatsby-plugin-flow`,

`gatsby-plugin-sass`,
{
  resolve: 'gatsby-plugin-sitemap',
  options: {
    query: `{
      site: nvaSite {
        siteMetadata {
          siteUrl
        }
      }
      allSitePage {
        edges {
          node {
            path
          }
        }
      }
    }`
  }
},
`gatsby-plugin-react-helmet`,
`@danbruegge/gatsby-plugin-stylelint`,
{
  resolve: 'gatsby-source-nva',
  options: {
    siteAdmin: getSiteAdminOptions(),
    yext: getYextOptions()
  }
},
{
  resolve: "gatsby-source-graphql",
  options: {
    typeName: "CGQL",
    fieldName: "CGQL",
    url: getContentFulUrl(),
    headers: getContentFulHeader(),
  },
}

]
`

gatsby-node.js
exports.createPages = require('./internal/hooks/createPages');

package.json
{ "name": "site-random", "version": "2.2.1", "description": "Random ", "main": "index.js", "repository": { "type": "git", "url": "someurl" }, "license": "UNLICENSED", "private": true, "scripts": { "storybook": "start-storybook -s ./src/static -p 6006", "build-storybook": "build-storybook -s ./src/static", "develop": "npm run clean && npx gatsby develop", "start": "npm run develop", "prebuild": "npm run clean", "build": "npx gatsby build", "serve": "npx gatsby serve", "flow": "flow", "flow:install": "flow-typed install", "lint:css": "stylelint './src/**/*.js'", "pretest": "npm run lint:css", "test": "jest --coverage=false", "test:update-snapshot": "jest --updateSnapshot --coverage=false", "test:coverage": "npm run clean:coverage && jest --coverage", "lighthouse": "concurrently --success=first --kill-others \"npm run serve\" \"lighthouse --output json --output html --output-path=./reports/lighthouse/homepage.json http://localhost:9000\"", "clean": "npm-run-all --parallel clean:*", "clean:coverage": "rimraf './reports/coverage'", "clean:cache": "rimraf ./.cache", "clean:logs": "rimraf ./output.log", "clean:public": "rimraf ./public", "deploy": "node azure/deploy.js", "log": "node azure/send-logs.js", "semantic-release": "semantic-release" }, "author": "Publicis Sapient", "dependencies": { "@contentful/rich-text-html-renderer": "^13.1.0", "@danbruegge/gatsby-plugin-stylelint": "^3.4.0", "@storybook/addon-actions": "^4.0.2", "@storybook/addon-links": "^4.0.2", "@storybook/addons": "^4.0.2", "@storybook/react": "^4.0.2", "applicationinsights": "^1.1.0", "babel-loader": "^8.0.4", "babel-plugin-styled-components": "^1.8.0", "crypto": "^1.0.1", "details-polyfill": "^1.1.0", "enquire.js": "^2.1.6", "formik": "^1.4.1", "gatsby": "^2.3.13", "gatsby-cli": "^2.5.5", "gatsby-plugin-flow": "^1.0.4", "gatsby-plugin-react-helmet": "^3.0.12", "gatsby-plugin-react-svg": "^2.1.1", "gatsby-plugin-robots-txt": "^1.4.0", "gatsby-plugin-root-import": "^2.0.5", "gatsby-plugin-sass": "^2.0.11", "gatsby-plugin-sitemap": "^2.0.11", "gatsby-plugin-styled-components": "^3.0.7", "gatsby-plugin-typography": "^2.2.10", "gatsby-source-contentful": "^2.0.9", "gatsby-source-graphql": "^2.0.18", "normalize.css": "^8.0.1", "polished": "^3.2.0", "prop-types": "^15.6.2", "react": "^16.6.0", "react-aria-modal": "^3.0.1", "react-datepicker": "^2.0.0", "react-dom": "^16.6.0", "react-helmet": "^5.2.0", "react-responsive-carousel": "^3.1.43", "react-responsive-picture": "^3.1.0", "react-slick": "^0.23.2", "react-storybook-addon-chapters": "^2.1.9", "react-typography": "^0.16.19", "slick-carousel": "^1.8.1", "styled-components": "^4.0.3", "stylelint": "^9.8.0", "stylelint-config-recommended": "^2.1.0", "stylelint-config-styled-components": "^0.1.1", "stylelint-custom-processor-loader": "^0.5.0", "stylelint-processor-styled-components": "^1.5.0", "stylelint-webpack-plugin": "^0.10.5", "typography": "^0.16.19", "url-slug": "^2.0.0", "util": "^0.11.1", "uuid": "^3.3.2", "winston": "^3.2.1", "winston-azure-application-insights": "^2.0.0", "yup": "^0.26.6" }, "devDependencies": { "@azure/storage-blob": "^10.2.0-preview", "@babel/core": "^7.1.6", "@commitlint/cli": "^7.2.1", "@commitlint/config-conventional": "^7.1.2", "@semantic-release/changelog": "^3.0.2", "@semantic-release/commit-analyzer": "^6.1.0", "@semantic-release/git": "^7.0.8", "@semantic-release/npm": "^5.1.4", "@semantic-release/release-notes-generator": "^7.1.4", "babel-core": "^7.0.0-bridge.0", "babel-jest": "^23.6.0", "babel-preset-gatsby": "^0.1.11", "concurrently": "^4.1.0", "cross-env": "^5.2.0", "dotenv": "^6.1.0", "enzyme": "^3.7.0", "enzyme-adapter-react-16": "^1.7.0", "eslint": "^5.8.0", "eslint-plugin-flowtype": "^3.2.0", "eslint-plugin-import": "^2.14.0", "eslint-plugin-jsx-a11y": "^6.1.2", "eslint-plugin-react": "^7.11.1", "flow-bin": "^0.86.0", "flow-typed": "^2.5.1", "husky": "^1.1.2", "identity-obj-proxy": "^3.0.0", "jest": "^23.6.0", "jest-junit": "^6.2.1", "jest-sonar-reporter": "^2.0.0", "jest-styled-components": "^6.3.1", "lighthouse": "^4.0.0-alpha.2-3.2.1", "lint-staged": "^8.0.4", "lodash.find": "^4.6.0", "mime-types": "^2.1.21", "npm": "^6.4.1", "npm-run-all": "^4.1.5", "react-test-renderer": "^16.6.3", "rimraf": "^2.6.2", "semantic-release": "^15.13.3", "stylelint-order": "^2.0.0" } }

stale?

Most helpful comment

For me it was that if the pictures where not in responsive mode all worked out but as soon as I reached the breakpoints the images appeared in the wrong card. After useEffect it worked.

Here my final code
`import React, { useState, useEffect } from 'react';
import Slider from 'react-slick';
import Card02 from '../card02/Card02';
import './slick-theme.css';
import './slick.css';

const SlickCarousel = props => {
const [isRendered, setIsRendered] = useState(false);
{
var settings = {
slidesToShow: 3,
slidesToScroll: 1,
swipeToSlide: true,
infinite: true,
autoplay: true,
autoplaySpeed: 3500,
dots: true,

  responsive: [
    {
      breakpoint: 1000,
      settings: {
        slidesToShow: 2,
      },
    },
    {
      breakpoint: 675,
      settings: {
        slidesToShow: 1,
        autoplay: false,
      },
    },
  ],
};

useEffect(() => {
  setIsRendered(true);
}, []);

if (!isRendered) {
  return <h3>Loading...</h3>;
} else
  return (
    <Slider {...settings}>
      {props.data.map(element => (
        <Card02
          key={element.id}
          title={element.title}
          img={element.img}
          subTitle={element.subTitle}
          desc={element.desc}
          classAdd="card02-slick"
        />
      ))}
    </Slider>
  );

}
};

export default SlickCarousel;
`

All 8 comments

This is most likely caused by react-slick rendering different DOM structure in server side render and client side rendering. This is mentioned in react docs ( https://reactjs.org/docs/react-dom.html#hydrate ):

React expects that the rendered content is identical between the server and the client. It can patch up differences in text content, but you should treat mismatches as bugs and fix them.

There are no guarantees that attribute differences will be patched up in case of mismatches. This is important for performance reasons because in most apps, mismatches are rare, and so validating all markup would be prohibitively expensive.

Also because server side rendering doesn't have concept of window width (there is no window when we produce static html), this is pretty difficult to solve (especially if react-slick changes DOM structure based on window width (at least when using responsive settings - I'm not that familiar with slick/react-slick)

@CyberV,

I had the same issue today I fixed it by not rendering the slider until the component is mounted as shown in the below code. I hope this helps!

Screen Shot 2019-05-03 at 3 58 39 PM

Hiya!

This issue has gone quiet. Spooky quiet. 馃懟

We get a lot of issues, so we currently close issues after 30 days of inactivity. It鈥檚 been at least 20 days since the last update here.

If we missed this issue or if you want to keep it open, please reply here. You can also add the label "not stale" to keep this issue open!

As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request. Check out gatsby.dev/contributefor more information about opening PRs, triaging issues, and contributing!

Thanks for being a part of the Gatsby community! 馃挭馃挏

Hey again!

It鈥檚 been 30 days since anything happened on this issue, so our friendly neighborhood robot (that鈥檚 me!) is going to close it.

Please keep in mind that I鈥檓 only a robot, so if I鈥檝e closed this issue in error, I鈥檓 HUMAN_EMOTION_SORRY. Please feel free to reopen this issue or create a new one if you need anything else.

As a friendly reminder: the best way to see this issue, or any other, fixed is to open a Pull Request. Check out gatsby.dev/contribute for more information about opening PRs, triaging issues, and contributing!

Thanks again for being part of the Gatsby community!

@CyberV were you able to resolve this problem with something like @victsant's solution? If not, do you wish for this to reopened?

,I have the same problem. The slider "works" but the pictures are not shown. I tried to solve the method as @CyberV BUT. It did not help. All the same. :-(

For me it was that if the pictures where not in responsive mode all worked out but as soon as I reached the breakpoints the images appeared in the wrong card. After useEffect it worked.

Here my final code
`import React, { useState, useEffect } from 'react';
import Slider from 'react-slick';
import Card02 from '../card02/Card02';
import './slick-theme.css';
import './slick.css';

const SlickCarousel = props => {
const [isRendered, setIsRendered] = useState(false);
{
var settings = {
slidesToShow: 3,
slidesToScroll: 1,
swipeToSlide: true,
infinite: true,
autoplay: true,
autoplaySpeed: 3500,
dots: true,

  responsive: [
    {
      breakpoint: 1000,
      settings: {
        slidesToShow: 2,
      },
    },
    {
      breakpoint: 675,
      settings: {
        slidesToShow: 1,
        autoplay: false,
      },
    },
  ],
};

useEffect(() => {
  setIsRendered(true);
}, []);

if (!isRendered) {
  return <h3>Loading...</h3>;
} else
  return (
    <Slider {...settings}>
      {props.data.map(element => (
        <Card02
          key={element.id}
          title={element.title}
          img={element.img}
          subTitle={element.subTitle}
          desc={element.desc}
          classAdd="card02-slick"
        />
      ))}
    </Slider>
  );

}
};

export default SlickCarousel;
`

solved my problem! thank you!

Was this page helpful?
0 / 5 - 0 ratings