19

I am trying to work on a project which is using a Layout/Template which uses a lot of jQuery.

I have learned to integrate the template with ReactJS Project, however, I am looking for a solution where I can completely replace the jQuery.

One of my solution is to use jQuery functions inside ComponentDidMount() or Render() function of React.

Is this approach correct? Is it the right way?

I have attached a small example below:

import React, { Component } from 'react';
import '../stylesheets/commonstyles.css';
import '../stylesheets/bootstrap-sidebar.css';
import '../stylesheets/sidebar1.css';
import $ from 'jquery';
 class NavBar extends Component {
   constructor(props){

      super(props);
      this.openSidebar = this.openSidebar.bind(this);

   }

  openSidebar(){

      console.log('hello sidebar');

  }
  componentWillMount(){

    $(document).ready(function () {
        $('#sidebarCollapse').on('click', function () {
            $('#sidebar').toggleClass('active');
        });
        $('.search-btn').on("click", function () {
          $('.search').toggleClass("search-open");
            return false;
           });

    });

}

This is my Render Function.

{/* <!--- SIDEBAR -------> */}
 <div class="wrapper" style={{paddingTop:60}}>
           {/* <!-- Sidebar Holder --> */ }
            <nav id="sidebar">
                <div class="sidebar-header">
                    <h3>Dashboard</h3>
                    <strong>BS</strong>
                </div>

                <ul class="list-unstyled components">
                    <li class="active">
                        <a href="#homeSubmenu" /*data-toggle="collapse" */ aria-expanded="false">
                            <i class="ti-home"></i>
                            Home
                        </a>
                        <ul class="collapse list-unstyled" id="homeSubmenu">
                            <li><a href="#">Home 1</a></li>
                            <li><a href="#">Home 2</a></li>
                            <li><a href="#">Home 3</a></li>
                        </ul>
                    </li>
                    <li>
                        <a href="#" style={{color:"white"}}>
                            <i class="ti-align-justify" ></i>
                            About
                        </a>
                        <a href="#pageSubmenu" /*data-toggle="collapse" */ aria-expanded="false" style={{color:"white"}}>
                            <i class="ti-text"></i>
                            Pages
                        </a>
                        <ul class="collapse list-unstyled" id="pageSubmenu">
                            <li><a href="#">Page 1</a></li>
                            <li><a href="#">Page 2</a></li>
                            <li><a href="#">Page 3</a></li>
                        </ul>
                    </li>
                    <li>
                        <a href="#" style={{color:"white"}}>
                            <i class="ti-paragraph"></i>
                            Portfolio
                        </a>
                    </li>
                    <li>
                        <a href="#" style={{color:"white"}}>
                            <i class="ti-control-play"></i>
                            FAQ
                        </a>
                    </li>
                    <li>
                        <a href="#" style={{color:"white"}}>
                            <i class="ti-share-alt"></i>
                            Contact
                        </a>
                    </li>
                </ul>
            </nav>

            { /* <!-- Page Content Holder --> */ }
            <div id="content">  


            </div>
        </div>
Ivan
  • 34,531
  • 8
  • 55
  • 100
codemt
  • 413
  • 2
  • 9
  • 25
  • 8
    Uh, just don't. Use jQuery OR React, not both together (same with Angular or Vue) – Jeremy Thille Jul 12 '18 at 11:19
  • 1
    No because that doesn't explicitely solve OP's issue and doesn't make their code work. They need to rewrite _everything_ with React and drop jQuery entirely, but I'm not gonna do that in my answer :) – Jeremy Thille Jul 12 '18 at 11:25
  • 1
    As Jeremy said - you shouldn't use jQuery in react. In your example you are mounting js functions using jquery directly in the dom. Any direct dom manipulation is generally a very bad idea and will eventually end up in bad renders and things disappearing as states gets changed. – Fantastisk Jul 12 '18 at 11:27
  • 2
    Remove Jquery, replace your click toggles with react states, like this answer: https://stackoverflow.com/questions/42630473/react-toggle-class-onclick – Rence Jul 12 '18 at 11:28
  • 2
    @JeremyThille comment should be the answer. Also, if this component is at some point remounted, it will have as many zombie event making your application slower and slower. To prevent that, don't forget to use `$.off`. But you should not use jQuery as it is considered deprecated for many users since : `css3/webpack/querySelector/querySelectorAll/ReactJS/vue/....` – Dimitri Kopriwa Jul 12 '18 at 11:29
  • @Sirence Thanks. I was wondering then. Then how do you replace the animations, Pie Charts and other things which jquery provides? you can easily replace element toggling feature of jquery, but animations and other things, should one use Vanilla JS or another framework, to convert those jquery functions in the template, a and optimize it with react – codemt Jul 12 '18 at 11:54
  • In your first step, you can replace all your Jquery with vanilla JS if you want - all Javascript is also valid in React. Animations can even be handled in css for performance improvements. For all complex stuff you do not want to do yourself, there are a lot of lightweight react plugins that you can integrate in your project. – Rence Jul 12 '18 at 12:10
  • @Fantastisk that is not *universally* true. I do direct dom manipulation all the time, just outside the scope of react. some things cannot simply be done in react without a complete rewrite. like having a child mobile only route that needs to be able to hook the mobile menu and open it. would have required a complete rewrite of our app using context, instead a single line of code opens the modal by triggering a click on the hamburger, which is 100% safe, since react "reacts" to to the click event and does the rest. so please, speak clearly, only certain things are *truly unsafe* with react. – r3wt Jan 29 '19 at 18:56
  • @r3wt I totally agree. That was also why I wrote "generally". I also had cases where i had to do dom manipulation outside the scope of react. But I would ideally prefer to have dom manipulations living inside react. That said - I also had cases where dom manipulation outside react triggered unwanted layout because react "didn't know" that the dom was changed after render. My advice remains - keep any DOM manipulation inside react as much as possible. Keep in mind, it's only an advice. – Fantastisk Feb 03 '19 at 11:41

5 Answers5

42

Is this approach correct? Is it the right way?

No. No approach is correct and there is no right way to use both jQuery and React/Angular/Vue together.

jQuery manipulates the DOM by, for example, selecting elements and adding/deleting stuff into/from them. Typically, it selects an existing <div> and sets its text.

The other frameworks don't manipulate the DOM; they generate it from data, and regenerate it whenever this data changes (for instance after an Ajax call).

The problem is, jQuery has no clue about React's presence and actions, and React has no clue about jQuery's presence and actions.

This will necessarily lead to a broken application, full of hacks and workarounds, unmaintainable, not to mention that you have to load two libraries instead of one.

For instance, jQuery will select a <button> and add it a .click() listener; but a split second later, React/Angular/Vue might regenerate the DOM and the button in the process, voiding jQuery's .click(). So you'll ask a question on Stackoverflow, wondering why the heck does your .click() not work. You'll end up adding a dirty setTimeout() hack, in order to delay jQuery's click() handler attachment until after React has regenerated your button. It's straight up your highway to hell.

Solution : use jQuery OR (React/Angular/Vue), not both together.

Jeremy Thille
  • 26,047
  • 12
  • 43
  • 63
  • 12
    While you are right about the possibility of jQuery and React messing up each others states, I think its not right to say that the two must not be used together outright. An app can have both provided they are not mixed incorrectly. Please update your answer, Jeremy. There's nothing wrong in adding React to your stack incrementally. –  Jul 12 '18 at 11:49
  • Thanks. I was wondering then. Then how do you replace the animations, Pie Charts and other things which jquery provides? you can easily replace element toggling feature of jquery, but animations and other things, should one use Vanilla JS or another framework, to convert those jquery functions in the template, a and optimize it with react. – codemt Jul 12 '18 at 11:53
  • 1
    You said "jQuery manipulates the DOM". No. You can tell jQuery to do it. You can use jQuery in so many ways. Se, the answer should not be "no". It depends. There can be a way to use both, if the developer knows what it's doing. – gulima Sep 30 '20 at 11:47
  • 3
    The React documentation outlining how to properly mix libraries: https://reactjs.org/docs/integrating-with-other-libraries.html – ADJenks Oct 26 '21 at 20:58
  • After mounting, what is wrong if one use jquery for slide/animation purpose? Both then got raw DOM. ?? – Sabbir Sobhani Aug 05 '22 at 00:30
3

Is this approach correct? Is it the right way?

No. Don't use jQuery to attach event listeners to DOM elements created and managed by React. Use onClick'. I could not find#sidebarCollapse` in your snippet. It could look something like this.

<button id="sidebarCollapse" onClick={state => this.setState({ collapsed: !state.collapsed })>Collapse</button

And the class for <nav id="sidebar"> could dependent on this state

<nav id="sidebar" className={ this.state.collapsed ? "": "active" } >

You'll notice, you hand over running operations like adding removing class, attributes and other DOM operations to React and simply declare how things must react to state changes. Amidst this, if you try to run jQuery operations, your UI could probably end up in an inconsistent state.

Migration could be done like this: replace parts of your UI elements with React. For eg, initially you could do,

<!-- rest of your existing jQuery based code -->
<header id="reactManagedNavbar">
  <!-- Nothing here. React will take care of DOM Elements here -->
</header>
<!-- rest of your existing jQuery based code -->

And React side could look like this,

// main.js
ReactDOM.render(<MyNavBar />, document.getElementById('reactManagedNavBar'))

// MyNavBar.js could have the react components

This way you can incrementally migrate to React and still have jQuery side by side. Just dont manipulate the each other DOM elements.

Sometimes you need a jQuery plugins (animations, visualisations charts etc) inside a React component. Use refs!

class MyJQueryDependingComp extends React.Component {
  constructor(props) {
    super(props);
    this.myRef = React.createRef();
  }
  componentDidMount() {
    // this.myRef.current is the dom element. Pass it to jQuery
  }
  render() {
    return (
       {/* rest of React elements */}
       <div ref={this.myRef} />
       {/* rest of React elements */}
    );
  }
}

Again, refrain from touching your jQuery's DOM in React and vice versa.

0

I've recommend you to use a provider plugin in your webpack.config:

Is really simple to use, and it allows you to use jquery in all your project without importing the package in every file:

More Info Docs: https://webpack.js.org/plugins/provide-plugin/?

So you just have to add this plugin in your webpack.config file:

new webpack.ProvidePlugin({
  $: 'jquery',
  jQuery: 'jquery'
});
Ricardo Gonzalez
  • 1,827
  • 1
  • 14
  • 25
0

There is no real way to convert a Jquery template into a React template except literally go through all the selects and rewrite everything in React. The reason being, both these libraries manipulate the dom in different ways

Hypothesis
  • 1,208
  • 3
  • 17
  • 43
-1

jQuery and react can very well when together only if they don't interact with each other. If you choose to use jQuery use only jQuery to manipulate the dom not both. And way is to use jQuery outside the react Js file in your index.html Please note: this will work only if the page you query loads first

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
  • 6
    This answer could use a little clarification and maybe a small code example. –  Feb 15 '19 at 18:09