Recently I volunteered in building a site that reports whether certain websites are blocked locally (please don’t ask why that is happening). As it is a very simple app reporting status I wanted it to be easily scrape-able. One of the decision made was I want it to have things to see on first load, this practically removes the possibility of using react, which is my current favorite.
So there I have it, I am stuck with jQuery, my previous favorite tool. It is still capable, but after being spoilt by all the syntactic sugar in ES6 through the use of babel it is a bit an act of masochism writing in just ES5 syntax(I probably used the term wrongly and I don’t care).
Anyway, as told in the previous post I really like redux. And I want the user be able to do the API query to upstream by themselves whenever needed. This is because the backend caches upstream is a slower manner and information displayed on page may be irrelevant in any minute (especially during this election season, anything can happen in a snap of fingers).
Since I miss redux so much, therefore you know what would happen if you know me, I shoehorn hack them to work together, based on the connect
function in react-redux
var connect = _.partial(function(store, state_mapper, dispatcher_mapper) { return function($element) { return $element .data('store', store) .on('redux:dispatch', function(e, action) { e.preventDefault() store.dispatch(action) }) .on('redux:mapper_update', function(e) { e.preventDefault() state_mapper && $(this).data(state_mapper.call(this, store.getState())) }) .each(function() { store.subscribe(_.bind($(this).trigger, $(this), 'redux:mapper_update')) dispatcher_mapper && _.mapObject( dispatcher_mapper(store.dispatch), function(handler, event) { $(this).on(event, _.bind(handler, this)) }, this) store.subscribe(_.bind($(this).trigger, $(this), 'redux:render')) }) } }, Redux.createStore(reducer))
I miss arrow function.
So there’s nothing much to shout about the messy code (yes, it also requires underscore.js). I am going to skip straight to tell what it does.
So the snippet above already create a redux store through the _.partial
call. Feel free to fix that for your own use. So the resulting connect
function partially recreates what the real thing does, with the following exceptions.
- This is an ugly hack
- There’s no such thing as
props
in a jQuery element, so I store the state into the respective.data()
call for themapStateToProp
./li> - Decided not to hack so much so I treat the
mapDispatchToProp
argument as jQuery event handlers. - There’s no such thing as
render()
in jQuery, so I shoehorn the render as a custom eventredux:render
that is triggered after every change of state - The resulting function takes in a jQuery element instead of a react component (duh!)
Don’t judge me.
And this is how I abuse use it.
connect( function(state) { return { website: state.website[$(this).data('_website_uri')] || false } }, function(dispatch) { return { 'redux:render': function() { if($(this).data('website')) { $(this) .empty() .append($('<td>' + $(this).data('website').website_uri + '</td>')) } } } } )($('.category tbody tr')) .append(...) // function returns the same jQuery element so you can continue chaining the methods
Hey, at least it works as intended!
Anyway if you are interested in contributing to the website, the github repository is here, pull requests are welcomed. Please do not attempt to kill my jQuery-redux work prematurely lol.