Notes on codes, projects and everything

Shoehorning redux into jQuery web app

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.

  1. This is an ugly hack
  2. There’s no such thing as props in a jQuery element, so I store the state into the respective .data() call for the mapStateToProp./li>
  3. Decided not to hack so much so I treat the mapDispatchToProp argument as jQuery event handlers.
  4. There’s no such thing as render() in jQuery, so I shoehorn the render as a custom event redux:render that is triggered after every change of state
  5. 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.

leave your comment

name is required

email is required

have a blog?

This blog uses scripts to assist and automate comment moderation, and the author of this blog post does not hold responsibility in the content of posted comments. Please note that activities such as flaming, ungrounded accusations as well as spamming will not be entertained.

Click to change color scheme