Gatsby: How to use jQuery in a component with react owl carousel?

Created on 1 Jul 2019  路  13Comments  路  Source: gatsbyjs/gatsby

Hello at all,
I have installed the REACT-OWL-CAROUSEL with npm i react-owl-carousel in a local environment.
Then I build my component:

import React from 'react';
import OwlCarousel from 'react-owl-carousel';
import '../../../../node_modules/owl.carousel/dist/assets/owl.carousel.css';
import '../../../../node_modules/owl.carousel/dist/assets/owl.theme.default.css';
import './allKids.scss';


export default class Carousel extends React.Component {
  render() {
    return (
      <section className="allkids-area">
            <OwlCarousel
              className="owl-theme"
              loop
              margin={10}
              nav
              items={3}
            >
              <div className="item"><h4>1</h4></div>
              <div className="item"><h4>2</h4></div>
              <div className="item"><h4>3</h4></div>
              <div className="item"><h4>4</h4></div>
              <div className="item"><h4>5</h4></div>
              <div className="item"><h4>6</h4></div>
              <div className="item"><h4>7</h4></div>
              <div className="item"><h4>8</h4></div>
              <div className="item"><h4>9</h4></div>
              <div className="item"><h4>10</h4></div>
              <div className="item"><h4>11</h4></div>
              <div className="item"><h4>12</h4></div>
            </OwlCarousel>
      </section>
    )
  }
}

running "gatsby develop" is fine, but in the browser I get errors e.g.:

TypeError: Cannot read property 'fn' of undefined
(anonymous function)
node_modules/react-owl-carousel/umd/OwlCarousel.js:1758
1755 | * @todo Navigation plugin next and prev
1756 | * @public
1757 | */

1758 | $.fn.owlCarousel = function(option) {
1759 | var args = Array.prototype.slice.call(arguments, 1);
1760 |
1761 | return this.each(function() {
View compiled
(anonymous function)
node_modules/react-owl-carousel/umd/OwlCarousel.js:1795
1792 | /
1793 | $.fn.owlCarousel.Constructor = Owl;
1794 |
1795 | })(window.Zepto || window.jQuery, window, document);
1796 | (function($, window, document, undefined) {
1797 |
1798 | /
*
View compiled
(anonymous function)
node_modules/react-owl-carousel/umd/OwlCarousel.js:2
1 | (function (global, factory) {
2 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('react')) :
3 | typeof define === 'function' && define.amd ? define(['react'], factory) :
4 | (global.ReactOwlCarousel = factory(global.React));
5 | }(this, (function (React) { 'use strict';
View compiled
./node_modules/react-owl-carousel/umd/OwlCarousel.js
node_modules/react-owl-carousel/umd/OwlCarousel.js:5
2 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('react')) :
3 | typeof define === 'function' && define.amd ? define(['react'], factory) :
4 | (global.ReactOwlCarousel = factory(global.React));
5 | }(this, (function (React) { 'use strict';
6 |
7 | var React__default = 'default' in React ? React['default'] : React;
8 |
View compiled
__webpack_require__
/Volumes/Workbench/htdocs/music/webpack/bootstrap:723
720 | };
721 |
722 | // Execute the module function
723 | modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId));
724 |
725 | // Flag the module as loaded
726 | module.l = true;
View compiled
fn

... and so on

Can anybody help with easy understanding words? Thanks!

awaiting author response question or discussion

Most helpful comment

So I actually may have found a solution. It works on my machine:

Add jQuery to the html.js file.

Copy the .cache/default-html.js to src/html.js

Then in it, add a script tag for jQuery into the <head>

<script
    src="https://code.jquery.com/jquery-3.3.1.min.js"
    integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
    crossOrigin="anonymous"
  />

Tell webpack to find jQuery

If you don't have a gatsby-node.js file in your root, create one and drop this function in:

exports.onCreateWebpackConfig = ({
  actions,
}) => {
  const { setWebpackConfig } = actions;
  setWebpackConfig({
    externals: {
      jquery: 'jQuery', // important: 'Q' capitalized
    }
  })
}

This is to tell webpack to find jQuery.

Load the component with Loadable-components

Add @loadable/component to your site,

yarn add @loadable/component

And then this can be the file for your component:

import React from 'react';
import Loadable from '@loadable/component';
import '../../../../node_modules/owl.carousel/dist/assets/owl.carousel.css';
import '../../../../node_modules/owl.carousel/dist/assets/owl.theme.default.css';
import './allKids.scss';

const OwlCarousel = Loadable(() => import('react-owl-carousel'));

export default class Carousel extends React.Component {
  render() {
    return (
      <section className="allkids-area">
            <OwlCarousel
              className="owl-theme"
              loop
              margin={10}
              nav
              items={3}
            >
              <div className="item"><h4>1</h4></div>
              <div className="item"><h4>2</h4></div>
              <div className="item"><h4>3</h4></div>
              <div className="item"><h4>4</h4></div>
              <div className="item"><h4>5</h4></div>
              <div className="item"><h4>6</h4></div>
              <div className="item"><h4>7</h4></div>
              <div className="item"><h4>8</h4></div>
              <div className="item"><h4>9</h4></div>
              <div className="item"><h4>10</h4></div>
              <div className="item"><h4>11</h4></div>
              <div className="item"><h4>12</h4></div>
            </OwlCarousel>
      </section>
    )
  }
}

So now you are importing in the carousel using Loadable which will only load it in on the clientside and never on the serverside.

Then if you do yarn develop or yarn build the component will load in properly

All 13 comments

Looks like React owl carousel is a client side only package and isn't compatible with Gatsby build. You might want to look for a different react carousel that is compatible or try to get it working with https://www.gatsbyjs.org/docs/using-client-side-only-packages/#workaround-3-load-client-side-dependent-components-with-react-loadable

Feel free to reach out with any more questions you have.

@wardpeet Thanks a lot for your answer! So, according to your answer it is not possible to use React stuff in general in Gatsby?
But Gatsby is based on React. I can build in Gatsby classes based on React, right? But I can't use Third Party React tools in Gatsby?

@lesleyNilson yes you can. We support the full react ecosystem. Gatsby uses SSR (Server Side Rendering). This means your code needs to be executable outside of the browser. It looks like owl-carousel isn't a react component that supports SSR.

You can go for client-only routes which won't be executed on the server. You'll lose lots of speed optimisations so it's not really recommended.

This would make your owlCaourselwork on ssr but might not be what you need.

import React from 'react';
import OwlCarousel from 'react-owl-carousel';
import '../../../../node_modules/owl.carousel/dist/assets/owl.carousel.css';
import '../../../../node_modules/owl.carousel/dist/assets/owl.theme.default.css';
import './allKids.scss';


export default class Carousel extends React.Component {
  state = {
    isMounted: false,
  }
  componentDidMount() {
    this.setState({ isMounted: true });
  }
  render() {
    if (!this.state.isMounted) {
      return null;
    }

    return (
      <section className="allkids-area">
            <OwlCarousel
              className="owl-theme"
              loop
              margin={10}
              nav
              items={3}
            >
              <div className="item"><h4>1</h4></div>
              <div className="item"><h4>2</h4></div>
              <div className="item"><h4>3</h4></div>
              <div className="item"><h4>4</h4></div>
              <div className="item"><h4>5</h4></div>
              <div className="item"><h4>6</h4></div>
              <div className="item"><h4>7</h4></div>
              <div className="item"><h4>8</h4></div>
              <div className="item"><h4>9</h4></div>
              <div className="item"><h4>10</h4></div>
              <div className="item"><h4>11</h4></div>
              <div className="item"><h4>12</h4></div>
            </OwlCarousel>
      </section>
    )
  }
}

@wardpeet but I have installed the react version of owl carousel, as I wrote I have installed

npm i react-owl-carousel

And I got all the error messages. That's why I ask for using React in Gatsby

@lesleyNilson So what Ward is trying to put is that Gatsby is just React behind the scenes and all React components work in Gatsby, but some React components have to be setup so they are only used on the clientside as not all support Server Side Rendering

In this instance, react-owl-carousel uses jQuery and other native DOM APIs, but when you do gatsby build those APIs don't exist as you are building it in Node. That said, Ward's example shows a way to only make it render on the client instead of when it is being built which allows for it to properly build and then this component will load when React loads on the client.

I'd recommend trying out Ward's example and we can then discuss further things if that doesn't work.

@wardpeet @lannonbr Trying the command "gatsby develop" I got the error message " error 'setState' is not defined no-undef"

@lannonbr Is there a possibility to include jquery? And if yes, how?

So I am going to pull in @anamwp into this conversation as it seems they just had a similar situation of using this exact same component (https://github.com/gatsbyjs/gatsby/issues/15254)

They had a solution work for them, so @anamwp could you possibly help out as it sounds like you got this component working in your scenario.

So I actually may have found a solution. It works on my machine:

Add jQuery to the html.js file.

Copy the .cache/default-html.js to src/html.js

Then in it, add a script tag for jQuery into the <head>

<script
    src="https://code.jquery.com/jquery-3.3.1.min.js"
    integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8="
    crossOrigin="anonymous"
  />

Tell webpack to find jQuery

If you don't have a gatsby-node.js file in your root, create one and drop this function in:

exports.onCreateWebpackConfig = ({
  actions,
}) => {
  const { setWebpackConfig } = actions;
  setWebpackConfig({
    externals: {
      jquery: 'jQuery', // important: 'Q' capitalized
    }
  })
}

This is to tell webpack to find jQuery.

Load the component with Loadable-components

Add @loadable/component to your site,

yarn add @loadable/component

And then this can be the file for your component:

import React from 'react';
import Loadable from '@loadable/component';
import '../../../../node_modules/owl.carousel/dist/assets/owl.carousel.css';
import '../../../../node_modules/owl.carousel/dist/assets/owl.theme.default.css';
import './allKids.scss';

const OwlCarousel = Loadable(() => import('react-owl-carousel'));

export default class Carousel extends React.Component {
  render() {
    return (
      <section className="allkids-area">
            <OwlCarousel
              className="owl-theme"
              loop
              margin={10}
              nav
              items={3}
            >
              <div className="item"><h4>1</h4></div>
              <div className="item"><h4>2</h4></div>
              <div className="item"><h4>3</h4></div>
              <div className="item"><h4>4</h4></div>
              <div className="item"><h4>5</h4></div>
              <div className="item"><h4>6</h4></div>
              <div className="item"><h4>7</h4></div>
              <div className="item"><h4>8</h4></div>
              <div className="item"><h4>9</h4></div>
              <div className="item"><h4>10</h4></div>
              <div className="item"><h4>11</h4></div>
              <div className="item"><h4>12</h4></div>
            </OwlCarousel>
      </section>
    )
  }
}

So now you are importing in the carousel using Loadable which will only load it in on the clientside and never on the serverside.

Then if you do yarn develop or yarn build the component will load in properly

@lannonbr Your are awesome, it works!!
And I think it works without loadable because I got the message "2:8 warning 'Loadable' is defined but never used no-unused-vars
"

Alright, I am going to close this issue as this has been resolved.

Hello, @lannonbr for pull me here.
I think its much easier to import owl css directly rather that path from node modules.
Here is my component and how I use owl carousel in my component.
@lesleyNilson let me know if it helps you.

import React, { Component } from 'react';
import OwlCarousel from 'react-owl-carousel';
import 'owl.carousel/dist/assets/owl.carousel.css';
import 'owl.carousel/dist/assets/owl.theme.default.css';
import CarouselCard from './CarouselCard';
import {CarouselWrapper} from './Style';


export class Carousel extends Component {
    state= {
        responsive:{},
    }
    componentDidMount(){
        const desktop = this.props.desktop ? this.props.desktop : 4;
        const tablet = this.props.tablet ? this.props.tablet : 2;
        const mobile = this.props.mobile ? this.props.mobile : 1;
        this.setState({
            responsive:{
                0: {
                    items: mobile,
                },
                768: {
                    items: tablet,
                },
                1000:{
                    item: desktop
                }
            }
        })
    }

    render() {
        const posts = this.props.posts;
        const column = this.props.column ? this.props.column : 4;
        const gap = this.props.gap ? this.props.gap : 10;
        const loop = this.props.loop === false ? this.props.loop : true;
        const dots = this.props.dots === false ? this.props.dots : true;
        const nav = this.props.nav === false ? this.props.nav : true;
        const autoPlay = this.props.autoPlay === false ? this.props.autoPlay : true;
        return (
            <CarouselWrapper className="container">
                <div className="hero-body">
                    <div className="columns is-multiline is-1-mobile is-justified-center">
                        <OwlCarousel
                            className="owl-theme"
                            loop={loop}
                            margin={gap}
                            nav={nav}
                            dots={dots}
                            items={column}
                            autoplay={autoPlay}
                            responsive={this.state.responsive}
                        >
                            {
                                posts.edges.map( (item, index) => {
                                    return(
                                        <CarouselCard data={item.node} index={index} key={`item${index}`}/>
                                    )

                                } )
                            }
                        </OwlCarousel>
                    </div>
                </div>
            </CarouselWrapper>

        )
    }
}

export default Carousel

Thanks.

@wardpeet @lannonbr Trying the command "gatsby develop" I got the error message " error 'setState' is not defined no-undef"

Oh sorry, I've updated the example. It should have been this.setState. Loadable works to ^^

Was this page helpful?
0 / 5 - 0 ratings

Related issues

signalwerk picture signalwerk  路  3Comments

theduke picture theduke  路  3Comments

hobochild picture hobochild  路  3Comments

rossPatton picture rossPatton  路  3Comments

timbrandin picture timbrandin  路  3Comments