jQuery to React

Converting jQuery to React

Converting a single page web app from jQuery to React can be done several ways. This article shows how to integrate a single React component with a jQuery .click() method. The link to a live example is at the bottom of this article.

Example Code

All of the code for this project is available on GitHub at the link below.

https://github.com/joshkuhar/jquery-to-react

Setting Up

This example uses node.js and webpack. It requires the jquery module and a webpack plugin written for jquery. Install jquery from npm.

$ npm install --save jquery

The app’s webpack entry points to an index.js file. The jQuery code is written in the index.js file. The React component Table is imported into the index.js file where it is then embedded in the jQuery method.

Below is the webpack.config.js file. Be sure to include the new webpack.ProvidePlugin() plugin written to load jQuery from the node modules. Follow the example in the webpack.config.js file below for how to write the plugin.

var path = require('path');
var webpack = require('webpack');
module.exports = {
entry: './app/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'public/dist')
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: 'babel-loader',
options: {
presets: ['env']
}
}
},
{
test: /\.css$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' }
]
}
]
},
devtool: "cheap-source-map",
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
]
};

Integrating

Integrating React with jQuery can lead to a Goldilocks problem. Trying to find the right place to embed the React component may lead to several starts and stops. This is in part because of React’s asymmetrical flow of information. Data flows down while actions flow up.

jQuery to React App

The app takes a valid CSS color keyword from the user, such as Red or Blue, and displays the name of the color in a table and a matching colored tile underneath the table.

To demonstrate how some of the obstacles encountered when integrating React with jQuery can be overcome, the jQuery to React app is constrained to the following parameters.

  • The input must be handled by jQuery
  • The rendering of the table must be handled by React
  • The delete button for each row in the table must be handled by React
  • No more than five colors can be displayed

Communicating between jQuery and React

One of the obstacles encountered when integrating React into jQuery, is the lack of communication from the React component to the jQuery code wrapping it. For example, the React component can’t tell the jQuery on the outside that it deleted a row. However, React uses a virtual DOM to render elements into the real DOM. That’s where you get the information.

The jQuery Button

Below are the important parts of the jQuery button. The entire code for the jQuery button is shown after the explanations.

Find the color elements in the DOM

Use the jQuery .find() method to grab all of the elements rendered by React of the class ‘.td-color’. Then check it’s length. If it’s four or less, use the .map method to extract the innerText and create a new array called newColors.

$('#button').click(function(event){
event.preventDefault();
    var colors = $.find('.td-color')
    if(colors.length > 4){
alert("Only five colors can be displayed at a time.
Please delete one.")
return
}
    var newColors = colors.map( (color) => {
return color.innerText
})
...

Render the React Component

When integrating React as described in this article, the React component needs to be removed before rendering a new one. If there isn’t a React component rendered, the method returns false.

To remove the React component, use the .unmountComponentAtNode() method. To render the React Component, use the render() method.

$('#submit').click(function(event){
...
   ReactDOM.unmountComponentAtNode(
document.getElementById('root')
)
   ReactDOM.render(
<Table
colors={newColors}
/>,
document.getElementById('root')
)
})

jQuery Complete Code

Below is the complete code for a jQuery button.

$('#button').click(function(event){
event.preventDefault();
  var colors = $.find('.td-color')
  if(colors.length > 4){
alert("Only five colors can be displayed at a time.
Please delete one.")
return
}
  var newColors = colors.map( (color) => {
return color.innerText
})

var color = $('#color').val()
  var checked = checkColor(color.trim())
if (!checked) {
alert('Please enter a valid CSS color.')
return
}
  newColors.push(color)
  $('#color').val('')

ReactDOM.unmountComponentAtNode(
document.getElementById('root')
)
  ReactDOM.render(
<Table
colors={newColors}
/>,
document.getElementById('root')
)
})

The React Component

The React component is made up of four components: Table, Rows, Row, and Tiles.

Table

The React component Table is the highest component and controls the state of its children Row and Tile.

The data enters the component through the method componentWillMount() as this.props.colors

class Table extends React.Component {
constructor(props){
super(props)
this.onDelete = this.onDelete.bind(this)
this.state = {
colors: []
}
}
componentDidMount() {
this.setState({
colors: this.props.colors
})
}
onDelete(color) {
const colors = this.state.colors
for(var i in colors){
if(color == colors[i]){
colors.splice(i, 1)
}
}
this.setState({
colors: colors
})
}
render() {
return(
<div>
<div className='library-header'>React Component</div>
<table className='table-container'>
<Rows
colors={this.state.colors}
onDelete={this.onDelete}
/>
</table>
<Tiles colors={this.state.colors} />
</div>
)
}
}
export default Table

Rows

The Rows component creates a new array of Row components out of the array passed down as this.props.colors

class Rows extends React.Component {
render() {
let rows = this.props.colors.map( (color, index ) => {
return <Row
key={index}
color={color}
onDelete={this.props.onDelete}
/>
})
return (
<tbody>{rows}</tbody>
)
}
}
export default Rows

Row

The Row component includes the onClick action which calls the onDelete() method in the Table component at the top of the hierarchy. The method can be called because this.props.onDelete was passed down from Table. The color prop is passed in for its argument.

class Row extends React.Component {
render() {
const color = this.props.color
return (
<tr>
<td className='td-color'>
{color}
</td>
<td className='table-data td-click'
onClick={ () => this.props.onDelete( color ) } >
delete
</td>
</tr>
)
}
}
export default Row

Tiles

The Tiles component is a sibling of Rows in the hierarchy. The style attribute backgroundColor is set inside the component with the color from this.props.colors. The rest of the style attributes are declared in the CSS files.

The style attribute can be set with an object for example, the object {backgroundColor: color} is used to set the background color of the tile.

class Tiles extends React.Component {
render() {
let tiles = this.props.colors.map( ( color, index ) => {
return <div
className='tile'
style={ { backgroundColor: color } }
key={index}
></div>
})
return (
<div className='tiles'>{tiles}</div>
)
}
}
export default Tiles

jQuery and React

Below is an image of the app. jQuery handles the text field and submit button. The color name is then passed down to React and rendered in a table. The example below shows the app with the five color limit reached.

jQuery to React app with five color limit reached

Live App

Click on the link below to see the live app

Conclusion

Hopefully this method can help start conversion of your jQuery app to a React app. This example assumes all of the data is handled on the client.

If an app is using a server and database to store information, the same principles can be applied. Instead of gathering the data from the DOM, the jQuery component makes an AJAX call to the server. Then inside the React component, fetch can be used to delete colors from the database.

Thanks for reading.