1.0.0 • Published 6 years ago

vue-lens-mixin v1.0.0

Weekly downloads
-
License
MIT
Repository
gitlab
Last release
6 years ago

Vue Lens Mixin

Functional and fractal state management for Vue.js using lenses. (Proof of concept and probably not optimized for performance! Probably also not optimized for the best API)

  • Feels like local state, but is actually global state
  • Synchronization of state through out the component tree is automatic

Installation

npm install --save vue-lens-mixin

Usage

Your top-most component should have a state data containing the global state:

 <script>
   export default {
     name: 'App',
     data: function() {
       return {
+        state: {temperature: 80, wind: 42},
       };
     },
   };
 </script>

For every child component that needs a conversion layer from/to this global state, define the lens object {get, set} for the template.

 <script>
   export default {
     name: 'App',
     data: function() {
       return {
         state: {temperature: 80, wind: 42},

+        thermometerLens: {
+          get(state) {
+            const fahrenheit = state.temperature;
+            const celsius = Math.round(((fahrenheit - 32) * 5) / 9);
+            return celsius;
+          },
+
+          set(celsius, state) {
+            const fahrenheit = Math.round((celsius * 9) / 5 + 32);
+            return {...state, temperature: fahrenheit};
+          },
+        },
       };
     },
   };
 </script>

Notice that get and set is not the OOP style getters and setters, but instead its a pair of pure functions:

{
  get: parentState => childState,
  set: (newChild, oldParent?) => newParent
}

This lens should be passed on to child components using v-bind:lens=, for instance:

<template>
  <div id="app">
    <span>{{JSON.stringify(state)}}</span>
    <my-thermometer v-bind:lens="thermometerLens"/>
  </div>
</template>

To implement a component that expects a lens as prop, use the lens mixin. Notice also this component now expects its data to be under state:

import Vue from 'vue';
import * as lens from 'vue-lens-mixin';

Vue.component('my-thermometer', {
  mixins: [lens],
  template: `
    <div>
      <h1>European thermometer</h1>
      <button v-on:click="state -= 2">Colder</button>
      <button v-on:click="state += 2">Hotter</button>
      <h1>{{state}}°C</h1>
    </div>
  `,
});

This can be done for grandchildren components too. For instance, if my-thermometer has a child, just define a lens object in the my-thermometer, and render the child by passing the lens to it as props:

 import Vue from 'vue';
 import * as lens from 'vue-lens-mixin';

 Vue.component('my-thermometer', {
   mixins: [lens],
+  data: function () {
+    return {
+      childLens: {get: /* ... */, set: /* ... */}
+    }
+  },
   template: `
     <div>
       <h1>European thermometer</h1>
       <button v-on:click="state -= 2">Colder</button>
       <button v-on:click="state += 2">Hotter</button>
       <h1>{{state}}°C</h1>
+      <child-component v-bind:lens="childLens"/>
     </div>
   `,
 });

License

MIT

1.0.0

6 years ago