MithrilJS component with state management
Tags: mithriljs, component, state
Published: 2024-05-29 15:36:52

_This is my 11th write up on dev.to site. MithrilJS component and state management. A substantial part of the code was written by AI. Source code included._

## MithrilJS
[Mithril](https://mithril.js.org/) is an excellent JS framework, tiny and powerful. Like with another JS frameworks you can write components - a small piece of code solving a dedicated subtask.

## State management
Most of applications and most of JS frameworks implement state management - the way state is realized and maintained.

There are many ways to implement state management in Mithril. Excellent source of information is a blog post of Kevin Fiol: [Simple State Management in Mithril.js](https://kevinfiol.com/blog/simple-state-management-in-mithriljs/)

## Component 
In this example I have SVG component, logical OR gate. It has two inputs (A, B) and one output (Q). 
You can intend either internal component state (so component is independent) or global app state. And this is what I show you in this example.

### State
```js
const NodeState = (size) => Array(size).fill(false);

const NodeActions = (state) => ({
  setNode: (index, value) => {
    if (index >= 0 && index < state.length) {
      state[index] = value;
      m.redraw();  // Ensure Mithril redraws the view to reflect state changes
    }
  }
});
```

### OR gate
```js
const ORGate = {
  view: ({ attrs: { state, actions, idxA, idxB, idxQ } }) => {
    const inputA = state[idxA];
    const inputB = state[idxB];
    const output = inputA || inputB;

    // Update the output node state
    actions.setNode(idxQ, output);

    return m('div',
      m('svg', {
          viewBox: '0 0 100 100',
          width: '100',
          height: '100',
          xmlns: 'http://www.w3.org/2000/svg'
        },
        [
          // Input lines
          m('line', { onclick: () => actions.setNode(idxA, !inputA), x1: '0', y1: '30', x2: '30', y2: '30', stroke: inputA ? 'red' : 'blue', 'stroke-width': '2' }),
          m('line', { onclick: () => actions.setNode(idxB, !inputB), x1: '0', y1: '70', x2: '30', y2: '70', stroke: inputB ? 'red' : 'blue', 'stroke-width': '2' }),

          // OR gate rectangle
          m('rect', { x: '30', y: '20', width: '40', height: '60', fill: 'none', stroke: 'black', 'stroke-width': '2' }),

          // Output line
          m('line', { x1: '70', y1: '50', x2: '100', y2: '50', stroke: output ? 'red' : 'blue', 'stroke-width': '2' }),

          // Labels for inputs and output
          m('text', { onclick: () => actions.setNode(idxA, !inputA), x: '13', y: '25', 'text-anchor': 'middle', 'font-size': '12' }, 'A = ', inputA ? '1' : '0'),
          m('text', { onclick: () => actions.setNode(idxB, !inputB), x: '13', y: '65', 'text-anchor': 'middle', 'font-size': '12' }, 'B = ', inputB ? '1' : '0'),
          m('text', { x: '86', y: '40', 'text-anchor': 'middle', 'font-size': '12' }, 'Q = ', output ? '1' : '0'),
          // sign in gate
          m('text', {x: '45', y: '40', 'text-anchor': 'right', 'font-size': '18'}, "≥1")
        ]
      ),
    );
  }
};
```

### Short explanation
There is an array of values (initially: false values) called nodes. Nodes are used as fictive nodes in real logical circuit. Every gate has two inputs ("connected" to nodes) and one output ("connected" to node). All nodes are in one array; index is used to work with specific node (item of array). Indexes of nodes for inputs and output are put to the component via attributes.
```js
m(ORGate, { state: nodeState, actions: nodeActions, idxA: idxA, idxB: idxB, idxQ: 2 }),
```

### Source code
Complete source code with visualization is on [flems playground](https://flems.io/#0=N4IgtglgJlA2CmIBcBWAHAOhQTgDQgGMB7AOwGciFlDLYBDABzPihHzIICdbkBtABlz8AuvgBmEBGT6gSdMIiQgMACwAuYWGxok18XdRABfXLPmLlAK2n5iu-Wup2yagAQA5IlHgBlNXT1XAF5XAAoyCAAveABKYIA+VwBBTk46AE9wqNiMCVhYULE6WGYYgG4AHRIq5zdPbySCNQhSMmCwlwDYhLDgKtdXZjV6+CQwiBJvAA9cVwA3YoBXbqDEvpIBgYgxccn4Kdd4kP5XADJT1wnp1wAeQf89DAQSAHM1FTj1zc3OvV4r-bCdoLWDLSobb6uMAYTgsNIAd1C5QGAHoUa4AKLkRaw1wAWQg704klcsKgCLa73g8wg8HhrjURFJ8DECCa9y6rgIKjor3gZH6myMguFJCM5SqNVabgA8gAlADinJCXxpdLGoWArgCak4ZDGWt+8FmdCaLXIs2gUySlqgUwAQrapgBFVxGN1xVauVUDWqXEgMRZqJLtI3-O1JYTg75+iaBtT20MPeDhh1RwW+6WuIhB+PtONBkMAHyL-vj9vBGdcaNcAFUGFBOVTs7mg64SF5qUaq6bmq0MEMRqErc7Zjm1PGJdUIQNYWocRswKEAORQCBzZe4KsDJfLshzF6b73byFzWnw+1EKZjZcnE4ARn4D6fm5P33h0HeN8f-FfM8hAwqPAEAvOo34vlu-4AVMmjkDe6gTkgaLwihGDwgAzBgRCcC8KIAExPvwKL7oeb5upBAEDLwZGouiACSAZtrAEz8jRUIrsxJDwEeWqkAQzEEAA1hqnqJL25pkAO8DDJ2w4RrMACEBbBjEsxTPeN6-rM6Qaa4y7oVprhTHhN4GUe6QmXpZmzC43CCaMZaFq4AD8elksurg3gARqC3GzHuupEPZAC0H5QO8y43nhHnihRlE7hxLE8dmJD8RAQkiT04n9oOslWo6rhKYxCaqUZum3uZ5UAOyGcZpmGRZN41UetlBQ5ymJq5y7uZ5ek+csR4BXZ8ChZ+KiRXp0UepBbE1vKrgvJysJNLyLwIGxu7LWoyXXlZDVRYZYVfnpAAshlASBYF6QAbIZeSwDeHZcS1gX2d59BCYNrUhUd41RTFqmSlBkJza2bicfAG2Jc9sxaupTUNeVKC1ZZy4-uZqPIy9w1jOOeZdT170Df530jb9E3LlNsVA-FtGuAAMnQXnwCUrhiNhjlqG0vJQC2E5BlDy56FM22wylaUZWEonamaOXSUOVo2oVylJKVu1o+h5lRSgg3C2owW8ty2EU5AMAIIN7O6MFETRBT95U-5IYhEeKsuXp94eZpy6A8D3y7nryV8QJwlS1lsvkFJMneHJDqKR1avfpr2k3tdOv+XrBupSoxs3qbcB+Xplv6zb3Hfg7emJs7lrFZ17ue3pv4+7T7FC-sovekZN5oNdWunYZrci5nRucCb0D5xbpDF9kdvl8urpV3z+N171FVN7TNYRC8GwTAtXSCwHsPqydaeuOkN5nbrbdD9nI83sSoHt8uRfW9P35oMuJiuBUICAKZE97fzEMiwgTxrwGFOAYoojCVlSlmdw8olSBBVIKM86pejajULqfUHcjQmnDmQJ0St8pOldO6cUPQfRcizK7EIYZFbpn-LGGuSYuipntPQmMWY8ZthCApYcxViylnjtA74NZ6yNkCM2LhbgOzeA5HoHseDI4KztKOReQYpxVjnAuFua4NxxT9iuEiPE2IoIvFeTSrhnxWL-M3X64EtJsQug-exNjaYwVgHBPSCEGBIRRCheEaFMLYVwgRJ8xEDzLjIiYMi1FfabBrAxPMEMBRxISsuCGgdUrB0yl6bKEdcrR0VnHfhatyqI3qkeOqe0MYVJsq9dq-C3bdRYPXZc-UC5DTaqNcKf1JoA30ZRXcGSxZB3SiHJEYc+z5PlnlO0BUirllKV7bS1UUa1NPqjZqdScac1rs0qArT2lfXqd0iK-1po03Xuieai1AhbVWutVJLcto7XWWfSah0xrn3OsBZxN07qSAenpJ6BdSbvVNIJY5w1Tm9Mpv0y58VQb83BixKG38CAQE4PxSGbBvQEHVlVE6R4CDvOXFjWYnBz5Hnuo9UgoL6ngs+iTE55N-rUyeUMpKYt4Z6Squ-FZN5yVGVRujbSmNDJgrUW4AmLSV5HOZdC1lfSLnTmbjWRmzNWbs04JzbmkwpX7zbpkiW4zpZ5MkgU+AMclYLMLAnd2SdT7a0voPQ2N9R5mw6c-EuM8YqO3aC7RpXUPYr0bgMgC-sjUjKyWMnJYlFGWpjvM+OalE692XKnF1+s3U5z0nnc2-lvWv3drPSuelq7liaSGr2oDBkrgPh3dW3d00X3TlfHNt881jwLYXSeL9bZlz9Xpee5apVVtaWG2a6JN7bw2LcyGHL61Ru9EfE+pLW16Qzh2im991ATytj6t+H9Zjfz-gAoBICBngLdFUKBQM-RJHcAAEQQdSJBEJTEai1DqPUBo5HGhllM-Blx5IgdjmBkhHpyFVkYfGJ2-7UyRmjJsWDQYy20LmewlDnCwb5kaecXZwj4nojEU2ICY6ZFdmTAooDSjZkujHGDDR-4tGcEXCuXRriDF7gibDEx55LzqzvK4H8ImIJsTse7cTTynFXTRtJ5u7jPHLm8b4-xgSsI4XwoRcJpE4nRLibEtV9FiquGSYLYZHdRmSwmbkhNMzCmgdtSpNSZTKrrKqfpBqqNrL3B2a7GVBy5W+ShV0pVcKVXN05TDKzMabNmvs1HK1RDlY1yWQ3dzvK1nVLFQjbGbUxgdSaYTPqIWFVhbGhTKmPsp2uBuUteAK1XiPKiyuF53K3kHSPJJ5cG7ZNqBTgC-ItKYuSraR9SF5WfqVfOey2rMpcMQws1yxtqzMtkuy-J7zgqJUMrHYFw5ZW9KkxhVV+FqqrkMyZizNo2rdXan1VIw1ItjXZNDnZ2jiaimpbg-ajW6a8InwHtmrOublz5q9X2w9Jah3Lng4GuD47Q3e3DZCSNL3o0mrjYBiSdHHPgec-aP795HWkszW211oPO3g+7ZDg9xa0aloDRWtDSOa2o+4w2uGXce7Jz7lm6+YOIf7qngOmH5Fh3M-28vdntWZ3+l3vIxdwOeKrpbf3LdVOd2XUfkWsXaN36f2-qcc9cTgHA1rdeyB0C-TuEfS+5Ux4P3ni-egzBf6cE49aAQp0BURxuig16ChqHgzML+HQ5DmZyBuCKzQ5MrCsNR5cGOnhfDEcEaEQi6sJGGxkepFI9snZ-00dx19lRjHkXMe+Kx9jq51xcc2LuIxfGnmmMExYqxYmHFPJ66Kxxvy5N96eUprBKmME+OQqhDCmmQk6aMVEjnrgjOXcSUxFiKTWvpJW7xOLprJml4c8lpzKt0sVQFTl4VbyfO7f80GtysqiYdJO+F6ri+0mWZ31j978bPuH6TcUxZVzZZU+NbNSa-GpLLfLN6XZYrB-UrYmY7FlGbZVObJ5OaOURXake5ZrBdTfdrRtTrD5brL5fnWYfrQbalQFEbelHZcbCFULabHpM7FVebRbVFRddFTFbFb+WGfFJqIlWYElHbI8SlU6Sg4bYFOlKAhyOgplRAxVZAuFdlTfD-MqJqflEA4QsAlxXLPSIVSVAvA7YLBAzpRgs5FAmrNA9EDVG7NmDmZSPVXmJ7ZXLncWN7WzH-A-JLa1AAu1VNB1AHIHTXYeD1ceQtKHBne2WHeHFnUPYNCdFHZ7duT-dwhLX-bwlLQnYnUnFOII9tLXXOWnEXftUucXT+ZcMtBHVneI5HWtCNJdDHAgvSZtPnXrDXfIkIwoz1Yo6HRnWHEdI8QwmXDLOokGadECWdTApI1Xc+Ndb5AXbdO+HXHoyIw3E9EAE3EAQBM3S9KsK3W9aBBJEgQkCAYobIf9B7Xmc1OwnVdCPCQvbwFJP0SjPwR3EYV4vQUIa6KcZ4zsRoIDdoEYf4iSUIF45MZjGsDEKYeQBgBAVwRYMgOgF4ByOgMgGdCYF4B4-kBkJkBwy4g1GBaPMDeDfgMoOmEYf0a4O7ZSZIKUIk-Kdoe8Mk7PDwIvAEA4ak0ze0IGKoaEMAHMXQUIKAIgAgRYBQXQDALyLwdIFvAYT9b-dib+XRHgpfKsJcJU9cFU4AfiVErBb+bgeEb+T+ZfAxeBLoMWI0MYME80r3TxSjYE73YkwrUDfKZ08DEcMYe45QtHUIOBRUG0w0ZMK0zsD4gDc1YMhoPBAhN0whOZN0v3FRMYdCSLH0+3V9C0oMrE0M3BIDCM+AB0i0J04k33eM4hMYE6FMgxO3Z9dM7BTM60vQHMiSPMgs4DRWGMkssDBMl0MYFASs1wYQWtdUkAFQTgABAZYc5U3FbU+gNEsYfUogQ04wWYE0xvDjevfyGkkMBvbjZSYxJ5NQdIBgGQ7kRrQSKUqYHcyEU8oSFgPM0MxDUQNiPiHkPkDUFYRIe0xLZRa0WYeADAfwHCaSDAG8+yKAbY+KcUXY4GXcTjTcrk8tMiXcPc2U2mQ848m8UCi8q8mMICW8qAe8+PfKJ8p5F81aByUID8rE1svHI-cDf8wC5EtQECvCsCiCyiKCi3AZQcic0Ib+Uc8cqsNEYchgFU7+OgVIDIbMHYCYPQNjYoLEgULY3i7+fwHyHFWGFwdIBAA0b+MACSl4CYYKRkUS5AL+EAe8WEMAI0o3GCvikAXUMSwzYc94MSkAJIccxUhylQNy7k5Sry1y3Fb+eUTylynyoKkAP00K+ywK9Y+3aK1S8K9Y6sp9ABc3ACUYlysctgGiBs-8-ShgUIYcPQMAaWFyqALUnUucy4Eqt2b+LyF4YKMkb+Xqeqxq9pI0y0Wq1ye8AYMYE4GIdi74S3ISlESczU3FPKjAAqoqwkeAUqnoOasAN2XqgAaj0g2v6tcHWo8m9nYsHPFHBG0GYDZCA2oA0n4GXLMAUGoBArRO0DsD0AMCUClKgHSCdwGAYDoBgAxP6qwCsuQy8ghReG4EWEmGCmIFgGwjGGYgfhBvgH0HBFFCqBhEXI+tcDXDIFhIyDGFZH2GQ0Wh8REwBtvSBjUCgFmHeHRv0pwgmH6uQ0gBIBhSTP+vmuQy+p+teD+sBxJohCBqEhBoFKgAhsoGhoWjSHSGQ0hrFvhBUDmuQ2fnhAHwG0L04H0tgGQy3VhpIDGAIAcHgE4CRrJt5lVGltENlvltJunElPat8nRv5sEkFrBuFrNrGHaSNutoaqapYFVAdqdvBtduZCgCRuMFEBAE4kEmkCQF4GuosEgCJEkG0BxC0CUG8X1DRDBoYEdpAqIDADGsJFHMkAAAE8IMB+AMB0J86E7YBpqJgMBrBtB0KLAOBiQGBHAjBhAjAgA). 
Hope this is useful for you, developers. A little note: chatGPT AI ​​did most of the work.