How to Use jQuery Libraries in the React Ecosystem

Kaloyan Kosev
Dev Labs
Published in
5 min readDec 30, 2016

--

TL;DR: If you just want to see the final code snippet, with annotated comments, and learn from it — here is a GIST for you.

Using jQuery libraries in the React ecosystem is possible!

I will show you an approach how to do it. We will create a React component that manages the jQuery plugin.

You can use this approach to integrate almost any jQuery plugin!

Here’s the plan:

  • Use React lifecycle methods to initialize and teardown the jQuery plugin;
  • Use React props as plugin configuration options and hook up to plugin’s methods events;
  • Destroy the plugin when component unmounts.

Let’s explore a practical example how to do that. We will use the jQuery UI Sortable plugin as an example.

Step 1: Initialize the jQuery plugin

This is one of the most confusing and misunderstood things.

In order to understand the key point here, let’s first recap — ReactJS uses a virtual DOM — a simplified and lightweight copy of the actual DOM. It allows React to do its computations within this abstract world and skip the actual DOM operations, often slow and browser-specific.

The Virtual DOM will always be faster than rendering in the actual DOM. It doesn’t matter what browser you’re using. This is just a fact.

Therefore, we need to initialize the library on the underlying <ul> DOM element. We can access it by assigning a ref attribute to the <ul> JSX element, returned from the render method. Then, we use that DOM node, pass it to jQuery and initialize the plugin.

class Sortable extends React.Component {
componentDidMount() {
this.$node = $(this.refs.sortable);
this.$node.sortable();
}
render() {
return (
<ul ref="sortable"></ul>
);
}
};

Our component will accept an array (list) of items (strings) as data prop. Let’s add this option too:

class Sortable extends React.Component {
// ... omitted for brevity
// jQuery UI sortable expects a <ul> list with <li>s.
renderItems() {
return this.props.data.map( (item, i) =>
<li key={i} className="ui-state-default">
<span className="ui-icon ui-icon-arrowthick-2-n-s"></span>
{ item }
</li>
);
}

render() {
return (
<ul ref="sortable">
{ this.renderItems() }
</ul>
);
}
};

And here’s how we can use the component in our code now:

const list = ['ReactJS', 'JSX', 'JavaScript', 'jQuery'];<Sortable data={list} />

# Step 2: Pass configuration options via props

Initialization is completed, but let’s see how we can add different configuration options. We will pass configurations via props.

In our case, we will configure the opacity of the helper while sorting. We’ll use the opacity option in the plugin configuration, that takes values from 0.01 to 1.

The plan is simply to get the incoming opacity prop and use it in the plugin configuration.

class Sortable extends React.Component {
// ... omitted for brevity
componentDidMount() {
this.$node = $(this.refs.sortable);
this.$node.sortable({
opacity: this.props.opacity
});

}
// ... omitted for brevity
};
// Optional: set the default props, in case none are passed
Sortable.defaultProps = {
opacity: 1
};

So now we can pass opacity to our <Sortable /> component:

<Sortable opacity={0.8} />

The same way, we can map any of the jQuery UI Sortable options.

Step 3: Hook-up custom functions on plugin events.

You will most probably need to hook-up on some of the plugin methods, in order to perform some React logic, for example manipulate the state.

Just like in the previous step, we will use props, but this time — we will pass a function.

Here’s how to do that:

class Sortable extends React.Component {
// ... omitted for brevity
componentDidMount() {
this.$node = $(this.refs.sortable);
this.$node.sortable({
opacity: this.props.opacity,
// Get the incoming onChange function
// and invoke it on the Sortable `change` event
change: (event, ui) => this.props.onChange(event, ui)

});
}
// ... omitted for brevity
};
// Optional: set the prop types
Sortable.propTypes = {
onChange: React.PropTypes.func.isRequired
};

So now we can pass a custom function onChange to our <Sortable /> component:

<Sortable
opacity={0.8}
onChange={
(event, ui) => console.log(‘DOM changed!’, event, ui)
}
/>

Step 4: Pass the future updates control to jQuery

Right after ReactJS adds the element in the actual DOM, we need to pass the future control to jQuery. Otherwise, ReactJS will re-render our component on every change, but we don’t want that.

We want ReactJS to render out component only once, and we want jQuery to be responsible for all future updates.

React lifecycle methods comes to the rescue!

We will use shouldComponentUpdate() and always return false to switch this feature off and to therefore — force a single-render of the component.

`shouldComponentUpdate()` is invoked before rendering when new props or state are being received. If `shouldComponentUpdate()` returns `false`, then `componentWillUpdate()`, `render()`, and `componentDidUpdate()` will not be invoked.

Then, we will use componentWillReceiveProps() — we compare this.props with nextProps and call jQuery UI sortable updates only when necessary. This way, ReactJS will never re-render our component, and jQuery will be responsible for all updates.

For this example, we will implement the enable/disable option of the jQuery UI Sortable:

class Sortable extends React.Component {
shouldComponentUpdate() {
return false;
}
componentWillReceiveProps(nextProps) {
if (nextProps.enable !== this.props.enable) {
this.$node.sortable(nextProps.enable ? 'enable' : 'disable');
}
}
// ... omitted for brevity
};
// Optional: set the default props, in case none are passed
Sortable.defaultProps = {
enable: true
};
// Optional: set the prop types
Sortable.propTypes = {
enable: React.PropTypes.bool
};

Step 5: Clean up the mess.

Most of the jQuery plugins provide a mechanism for cleaning up after themselves when they are no longer needed. jQuery UI Sortable provides an event that we can trigger to tell the plugin to unbind its DOM events and destroy.

React lifecycle methods comes to the rescue again and provides a mechanism to hook into when the component is being unmounted:

class Sortable extends React.Component {
// ... omitted for brevity
componentWillUnmount() {
// Clean up the mess when the component unmounts
this.$node.sortable('destroy');
}
// ... omitted for brevity
};

The Final Version

Plus, a jsfiddle DEMO here.

Conclusion

In the case where a library modifies the DOM, we try to keep React out of it’s way. React works best when it has full control of the DOM.

In cases where we want to use a jQuery library, React components are more of wrappers for the 3rd party libraries. Mostly by using the componentDidMount()/componentWillUnmount() to initialize/destroy the third party library. And props as a way of giving the parent a way of customizing the behavior of the third party library that the child wraps and to hook-up on plugin events.

If you are migrating a legacy jQuery application to React or maybe you just can’t find a React plugin that suits your needs in your case — this approach is a lifesaver!

PS: The article is based on one of my StackOverflow answers. The only difference is that this article covers more details why and how.

--

--

Front-End Engineer, currently focused on React, React Native, and NodeJS. In the 10k+ reputation club on StackOverflow. Maker. Nano influencer. superkalo.com