Did you know, you can use React without rewriting your whole app?
A client recently asked me for a shiny graph. They had an API that spits out a lot of data, and they wanted an interactive visualization that would help users make decisions. Deadline was tight, technology restrictions were “As long as it works”, and specs were loose.
“A-ha!”, I thought, “This is a job for React+d3.js!”. Small, well-contained, perfect. The best kind of project for testing new technologies.
But their web app was built in Joomla or WordPress or something. And their front-end stack was jQuery. When I asked the engineer about integration, he talked about framework plugins that create views in PHP and load JavaScript files and stuff.
React components as jQuery plugins. Oh god what have I done ... http://t.co/NAMnUuXDW6 pic.twitter.com/Oza0nKAvUK
— Swizec (@Swizec) August 10, 2015
Or scroll down for the gist.
This is a React component, <Counter />
. It counts button clicks.
Everything else is a normal old school website.
The React component is embedded as a normal jQuery plugin. These buttons access its state via jQuery methods:
jQuery 10x Button
jQuery Get Value
The real world can use <Counter />
as a jQuery plugin:
// src/integrate.js
$(".container .counter").clickCounter();
$(".btn-10x").click(function () {
$(".container .counter")
.clickCounter()[0]
.val(10);
});
$(".btn-get").click(function () {
var val = $(".container .counter")
.clickCounter()[0]
.val();
alert("Current counter value is: "+val);
});
Pretty nice, eh?
You can still use it as a React component too:
// example.jsx
const MyThing = React.createClass({
render: function () {
return (
<div>
<Counter />
</div>
)
}
});
And if all else fails, you have the function options:
// example.js
var RenderCounter = require('/path/to/counter.js');
RenderCounter(".container .counter");
// OR
window.RenderCounter(".container .counter");
// src/main.jsx
if (typeof jQuery !== 'undefined') {
(function ($) {
var pluginName = "clickCounter",
defaults = {
value: 0
};
function Plugin(element, options) {
this.element = element;
this.settings = $.extend({}, defaults, options);
this._defaults = defaults;
this._name = pluginName;
this.init();
}
$.extend(Plugin.prototype, {
init: function () {
this.component = React.render(
,
this.element
);
return this;
},
val: function (val) {
if (!arguments.length) {
return this.component.state.counter;
}else{
this.settings.value = val;
this.init();
}
}
});
$.fn[pluginName] = function (options) {
return this.map(function () {
if (!$.data(this, 'plugin_'+pluginName)) {
$.data(this, 'plugin_'+pluginName, new Plugin(this, options));
}
return $.data(this, 'plugin_'+pluginName);
});
};
})(jQuery);
}
Or check the code on Github, here.
~Swizec