CJQ

Componentized JQuery

by jeyssonguevara

HTML

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@4.5.3/dist/css/bootstrap.min.css">
<div id="app">

</div>

JavaScript

// Componentized JQuery
 (function($, exports) {

   function StatefulComponent(props, render) {
     const {
       key
     } = props;

     key === undefined && console.warn(`At [${render.name}]: Stateful components should have a 'key' prop in order to recover state if the parent component gets re-rendered.`);

     let state = [];
     let statesCount = 0;
     let changedIndexes = [];
     const effects = [];

     const reducibleState = {
       isNew: true,
       data: undefined,
       init: (initial) => {
         if (this.isNew) {
           this.data = initial;
         }
       }
     };

     let needsReRender = false;
     let $currentElement = undefined;

     const scheduleRender = () => {
       if (!needsReRender) {
         needsReRender = true;
         setTimeout(() => this.doRender(), 0);
       }
     };

     const tryRecoverState = () => {
       if (!key) {
         return;
       }
       const $recoveredElement = $(`[data-key="${key}"]`);
       if ($recoveredElement.length > 0) {
         $currentElement = $recoveredElement;
         state = JSON.parse($currentElement.attr('data-state'));
         reducibleState.init(JSON.parse($currentElement.attr('data-reducible-state')));
       }
     };

     const saveState = () => {
       if (key) {
         $currentElement.attr('data-key', key);
       }
       return $currentElement.attr({
         'data-state': JSON.stringify(state),
         'data-reducible-state': JSON.stringify(reducibleState.data || {}),
       });
     }

     tryRecoverState();

     const use = {
       state: (initial) => {
         const currentIndex = statesCount;

         if (!$currentElement) {
           state.push(initial);
         }

         statesCount++;

         return [
           state[currentIndex],
           (newValue, {
             shouldRender = true
           } = {}) => {
             state[currentIndex] = newValue;
             changedIndexes.push(currentIndex);

             if...